Merge branches 'dev_aliyun' and 'dev_aliyun2' of https://bdgit.educoder.net/Hjqreturn/educoder into dev_aliyun2

dev_aliyun2
杨树明 5 years ago
commit 8eef510ceb

@ -18,7 +18,7 @@ class Admins::ShixunSettingsController < Admins::BaseController
task_pass: params[:task_pass].present? ? params[:task_pass] : false,
code_hidden: params[:code_hidden].present? ? params[:code_hidden] : false,
vip: params[:vip].present? ? params[:vip] : false,
no_subject: params[:no_subject].present? ? params[:no_subject] : false
is_wechat_support: params[:is_wechat_support].present? ? params[:is_wechat_support] : false
}
@shixuns_type_check = MirrorRepository.pluck(:type_name,:id)
@ -135,6 +135,6 @@ class Admins::ShixunSettingsController < Admins::BaseController
def setting_params
params.permit(:use_scope,:excute_time,:close,:status,:can_copy,:webssh,:hidden,:homepage_show,:task_pass,
:code_hidden,:vip,:page_no,:id, :no_subject)
:code_hidden,:vip,:page_no,:id, :is_wechat_support, tag_repertoires:[])
end
end

@ -1242,7 +1242,7 @@ class ExercisesController < ApplicationController
normal_status(0, "正在下载中")
else
set_export_cookies
render exam_pdf: 'exercise_export/blank_exercise', filename: filename_, stylesheets: stylesheets, disposition: 'inline', type: "pdf_attachment.content_type", stream: false
render pdf: 'exercise_export/blank_exercise', filename: filename_, stylesheets: stylesheets, disposition: 'inline', type: "pdf_attachment.content_type", stream: false
end
end

@ -924,7 +924,7 @@ class HomeworkCommonsController < ApplicationController
def publish_homework
tip_exception("请至少选择一个分班") if params[:group_ids].blank? && @course.course_groups.size != 0
group_ids = params[:group_ids]&.reject(&:blank?)&.map(&:to_i)
group_ids = params[:group_ids]&.reject(&:blank?).map(&:to_i)
if params[:detail].blank?
tip_exception("缺少截止时间参数") if params[:end_time].blank?
tip_exception("截止时间不能早于当前时间") if params[:end_time] <= strf_time(Time.now)
@ -1070,7 +1070,7 @@ class HomeworkCommonsController < ApplicationController
homeworks = homeworks.published_no_end.includes(:homework_group_settings, :homework_detail_manual, :homework_challenge_settings)
course_students = @course.students
charge_group_ids = @course.charge_group_ids(current_user)
group_ids = params[:group_ids]&.reject(&:blank?)&.map(&:to_i)
group_ids = params[:group_ids]&.reject(&:blank?).map(&:to_i)
end_groups = charge_group_ids & group_ids if group_ids
homeworks.each do |homework|

@ -712,7 +712,8 @@ class PollsController < ApplicationController
tip_exception("发布时间不能为空") if params[:publish_time].blank?
tip_exception("截止时间不能为空") if params[:end_time].blank?
tip_exception("截止时间必须晚于发布时间") if params[:publish_time].to_time >= params[:end_time].to_time
tip_exception("截止时间不能晚于课堂结束时间(#{@course.end_date.end_of_day.strftime("%Y-%m-%d %H:%M")}") if @course.end_date.present? && params[:end_time].to_time > @course.end_date.end_of_day
tip_exception("截止时间不能晚于课堂结束时间(#{@course.end_date.end_of_day.strftime("%Y-%m-%d %H:%M")}") if
@course.end_date.present? && params[:end_time].to_time > @course.end_date.end_of_day
params_publish_time = params[:publish_time].to_time
params_end_time = params[:end_time].to_time

@ -26,7 +26,7 @@ class ShixunsController < ApplicationController
before_action :special_allowed, only: [:send_to_course, :search_user_courses]
before_action :shixun_marker, only: [:new, :create]
#before_action :validate_wachat_support, only: [:shixun_exec]
before_action :validate_wachat_support, only: [:shixun_exec]
skip_before_action :check_sign, only: [:download_file]
## 获取课程列表
@ -1187,11 +1187,11 @@ private
md5.hexdigest
end
# def validate_wachat_support
#
# if (params[:wechat].present? && !@shixun.is_wechat_support?)
# tip_exception(-5, "..")
# end
# end
def validate_wachat_support
if (params[:wechat].present? && !@shixun.is_wechat_support?)
tip_exception(-5, "..")
end
end
end

@ -17,13 +17,7 @@ class Weapps::SessionsController < Weapps::BaseController
# session[:wechat_user_extra].delete(:nickName)
# 绑定微信号
# open_user = OpenUsers::Wechat.find_by(uid: session_unionid)
# if open_user.present? && open_user.user_id.nil?
# open_user.update!(user_id: user.id)
# els
if user.wechat_open_user.blank?
OpenUsers::Wechat.create!(user: user, uid: session_unionid)
end
OpenUsers::Wechat.create!(user: user, uid: session_unionid) if user.wechat_open_user.blank?
successful_authentication(user)
end

@ -1,7 +1,7 @@
module SubjectsHelper
# 实训路径的发布状态
def publish_status subject, is_manager
def publish_status subject, is_manager, user
status = -1
if is_manager
status = 0 if subject.status == 0

@ -51,10 +51,7 @@ class Admins::ShixunSettingsQuery < ApplicationQuery
all_shixuns = all_shixuns.where(task_pass: params[:task_pass]) if params[:task_pass]
all_shixuns = all_shixuns.where(code_hidden: params[:code_hidden]) if params[:code_hidden]
all_shixuns = all_shixuns.where(vip: params[:vip]) if params[:vip]
if params[:no_subject]
shixun_ids = StageShixun.pluck(:shixun_id).uniq
all_shixuns = all_shixuns.published.where.not(id: shixun_ids)
end
all_shixuns = all_shixuns.where(is_wechat_support: params[:is_wechat_support]) if params[:is_wechat_support]
custom_sort(all_shixuns, params[:sort_by], params[:sort_direction])
end

@ -22,7 +22,7 @@ class Subjects::CourseUsedInfoService < ApplicationService
# choice_shixun_frequency: 选用该课程实训的次数
course_info = []
schools.find_in_batches do |s|
s.each do |school|
Parallel.each(s) do |school|
name = school.name
course_count = school.course_count
student_count = school.courses.joins(:course_members).where(course_members: {role: 4, course_id: course_ids}).size

@ -11,7 +11,7 @@ class Subjects::ShixunUsedInfoService < ApplicationService
position = stage.position
shixuns = stage.shixuns.includes(myshixuns: :games, homework_commons: :course)
shixuns.find_in_batches(batch_size: 1000) do |s|
s.each_with_index do |shixun, index|
Parallel.each_with_index(s, in_processes: 2) do |shixun, index|
stage = "#{position}-#{index+1}"
name = shixun.name
myshixuns = shixun.myshixuns

@ -13,7 +13,7 @@ class Subjects::UserUsedInfoService < ApplicationService
users_info = []
users = User.includes(myshixuns: :games).where(myshixuns: {shixun_id: shixun_ids}, games: {status: 2}, users: {is_test: false})
users.find_in_batches(batch_size: 500) do |u|
u.each do |user|
Parallel.each(u, in_processes: 2) do |user|
myshixuns = user.myshixuns.select{|m| shixun_ids.include?(m.shixun_id)}
name = "#{user.lastname}#{user.firstname}"
passed_myshixun_count = myshixuns.select{|m| m.status == 1}.size

@ -73,8 +73,8 @@
</div>
<div class="mr-5">
<label for="is_wechat_support">
<%= check_box_tag :no_subject, !@sort_json[:no_subject],@sort_json[:no_subject], class:"shixun-settings-select" %>
<span class="only_view">已发布没关联课程</span>
<%= check_box_tag :is_wechat_support, !@sort_json[:is_wechat_support],@sort_json[:is_wechat_support], class:"shixun-settings-select" %>
<span class="only_view">只看小程序可用</span>
</label>
</div>

@ -8,8 +8,7 @@ json.member_count @subject.member_count
json.is_collect @user&.is_collect?(@subject)
json.allow_delete (@subject.status != 2 && @is_creator) || @user.admin?
json.publish_status publish_status(@subject, @is_manager)
json.public_status public_status(@subject, @is_manager, @user)
json.publish_status publish_status(@subject, @is_manager, @user)
json.allow_statistics @is_manager
json.allow_send @user.logged?
json.allow_visit @subject.status > 1 || @is_manager

@ -5,4 +5,4 @@ json.end_time attendance.end_time.strftime("%H:%M")
student_attendance_status = student_attendance_status(attendance, User.current)
json.attendance_status student_attendance_status[:attendance_status]
json.attendance_mode student_attendance_status[:attendance_mode]
json.attendance_mode student_attendance_status[:attendance_mode]

@ -1376,4 +1376,4 @@ B样
垃 圾
傻 逼
真蠢
蠢猪
蠢猪

@ -5,14 +5,12 @@ namespace :subjects do
puts("---------------------data_statistic_begin")
Rails.logger.info("---------------------data_statistic_begin")
subjects = Subject.where(status: 2, hidden: 0)
if ENV['subject_id'].present?
subjects = subjects.where(id:ENV['subject_id'])
end
str = ""
buffer_size = 0
column_value = "subject_id, study_count, course_study_count, initiative_study, passed_count, course_used_count, " +
"school_used_count, created_at, updated_at"
subjects.find_in_batches(batch_size: 50) do |s|
str = []
Parallel.each_with_index(s, in_threads: 4) do |subject, index|
subjects.find_in_batches(batch_size: 50) do |s, index|
Parallel.each_with_index(s, in_processes: 4) do |subject|
puts("---------------------data_statistic: #{subject.id}")
Rails.logger.info("---------------------data_statistic: #{subject.id}")
data = Subjects::DataStatisticService.new(subject)
@ -20,16 +18,18 @@ namespace :subjects do
next if study_count == 0
course_study_count = data.course_study_count
initiative_study = study_count - course_study_count
str << ("(#{subject.id}, #{study_count}, #{course_study_count}, #{initiative_study}, " +
str += ", " unless str.empty?
str += ("(#{subject.id}, #{study_count}, #{course_study_count}, #{initiative_study}, " +
"#{data.passed_count}, #{data.course_used_count}, #{data.school_used_count}, " +
"'#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}')")
puts "index: #{index}; worker_number: #{Parallel.worker_number}"
puts "####str: #{str}"
end
if str.size > 0
sql = "REPLACE INTO subject_records(#{column_value}) VALUES #{str.uniq.join(",")}"
puts sql
ActiveRecord::Base.connection.execute sql
buffer_size += 1
if buffer_size == 1000 || subjects.count == (index+1)
sql = "REPLACE INTO subject_records(#{column_value}) VALUES #{str}"
puts sql
ActiveRecord::Base.connection.execute sql
str = ""
buffer_size = 0
end
end
end
@ -41,33 +41,30 @@ namespace :subjects do
puts("---------------------course_info_statistic_begin")
Rails.logger.info("---------------------course_info_statistic_begin")
subjects = Subject.where(status: 2, hidden: 0)
str = ""
buffer_size = 0
column_value = "subject_id, school_id, school_name, course_count, student_count, choice_shixun_num, " +
"choice_shixun_frequency, created_at, updated_at"
if ENV['subject_id'].present?
subjects = subjects.where(id:ENV['subject_id'])
end
subjects.find_in_batches(batch_size: 20) do |s|
Parallel.each_with_index(s, in_processes: 4) do |subject, index, str = []|
subjects.find_in_batches(batch_size: 50) do |s|
Parallel.each(s, in_processes: 4) do |subject|
puts("---------------------course_info_statistic: #{subject.id}")
Rails.logger.info("---------------------course_info_statistic: #{subject.id}")
data = Subjects::CourseUsedInfoService.call(subject)
data.each do |key|
Parallel.map_with_index(data) do |key, index|
next if key[:school_id].nil?
str << ("(#{subject.id}, #{key[:school_id]}, '#{key[:school_name]}', #{key[:course_count]}, " +
str += ", " unless str.empty?
str += ("(#{subject.id}, #{key[:school_id]}, '#{key[:school_name]}', #{key[:course_count]}, " +
"#{key[:student_count]}, #{key[:choice_shixun_num]}, #{key[:choice_shixun_frequency]}, " +
"'#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}')")
# if str.size == 1000
# sql = "REPLACE INTO subject_course_records(#{column_value}) VALUES #{str.uniq.join(",")}"
# str_c = str
# puts sql
# ActiveRecord::Base.connection.execute sql
# str -= str_c
# end
end
if str.size > 0
sql = "REPLACE INTO subject_course_records(#{column_value}) VALUES #{str.uniq.join(",")}"
puts sql
ActiveRecord::Base.connection.execute sql
buffer_size += 1
if buffer_size == 1000 || (index + 1) == data.size
sql = "REPLACE INTO subject_course_records(#{column_value}) VALUES #{str}"
puts sql
ActiveRecord::Base.connection.execute sql
str = ""
buffer_size = 0
end
end
end
end
@ -79,32 +76,30 @@ namespace :subjects do
puts("---------------------shixun_info_statistic_begin")
Rails.logger.info("---------------------shixun_info_statistic_begin")
subjects = Subject.where(status: 2, hidden: 0)
if ENV['subject_id'].present?
subjects = subjects.where(id:ENV['subject_id'])
end
str = ""
buffer_size = 0
column_value = "subject_id, shixun_id, stage, shixun_name, challenge_count, course_count, " +
"school_count, used_count, passed_count, evaluate_count, passed_ave_time, created_at, updated_at"
subjects.find_in_batches(batch_size: 20) do |s|
Parallel.each_with_index(s, in_processes: 4) do |subject, index, str = []|
subjects.find_in_batches(batch_size: 50) do |s|
Parallel.each_with_index(s, in_processes: 4) do |subject|
puts("---------------------shixun_info_statistic: #{subject.id}")
Rails.logger.info("---------------------shixun_info_statistic: #{subject.id}")
data = Subjects::ShixunUsedInfoService.call(subject)
data.each do |key|
data.each_with_index do |key, index|
next if key[:shixun_id].nil?
str << ("(#{subject.id}, #{key[:shixun_id]}, '#{key[:stage]}', '#{key[:name]}', #{key[:challenge_count]}, " +
str += ", " unless str.empty?
str += ("(#{subject.id}, #{key[:shixun_id]}, '#{key[:stage]}', '#{key[:name]}', #{key[:challenge_count]}, " +
"#{key[:course_count]}, #{key[:school_count]}, #{key[:used_count]}, #{key[:passed_count]}, " +
"#{key[:evaluate_count]}, #{key[:passed_ave_time]}, " +
"'#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}')")
# if str.size == 1000
# sql = "REPLACE INTO subject_shixun_infos(#{column_value}) VALUES #{str.join(",")}"
# puts sql
# ActiveRecord::Base.connection.execute sql
# end
end
if str.size > 0
sql = "REPLACE INTO subject_shixun_infos(#{column_value}) VALUES #{str.join(",")}"
puts sql
ActiveRecord::Base.connection.execute sql
buffer_size += 1
if buffer_size == 1000 || (index+1) == data.size
sql = "REPLACE INTO subject_shixun_infos(#{column_value}) VALUES #{str}"
puts sql
ActiveRecord::Base.connection.execute sql
str = ""
buffer_size = 0
end
end
end
end
@ -116,26 +111,28 @@ namespace :subjects do
puts("---------------------user_info_statistic_begin")
Rails.logger.info("---------------------user_info_statistic_begin")
subjects = Subject.where(status: 2, hidden: 0)
str = ""
buffer_size = 0
column_value = "user_id, subject_id, username, passed_myshixun_count, passed_games_count, " +
"code_line_count, evaluate_count, cost_time, created_at, updated_at"
subjects.find_in_batches(batch_size: 20) do |s|
Parallel.each_with_index(s, in_processes: 4) do |subject, index, str = []|
subjects.find_in_batches(batch_size: 50) do |s|
Parallel.each_with_index(s, in_processes: 4) do |subject, index|
puts("---------------------user_info_statistic: #{subject.id}")
data = Subjects::UserUsedInfoService.call(subject)
data.each do |key|
str << ("(#{key[:user_id]}, #{subject.id}, '#{key[:name].gsub(/'/, '"')}', #{key[:passed_myshixun_count]}, " +
next if key[:user_id].nil?
str += ", " unless str.empty?
str += ("(#{key[:user_id]}, #{subject.id}, '#{key[:name].gsub(/'/, '"')}', #{key[:passed_myshixun_count]}, " +
"#{key[:passed_games_count]}, #{key[:code_line_count]}, #{key[:evaluate_count]}, #{key[:cost_time]}, " +
"'#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}')")
# if str.size == 1000
# sql = "REPLACE INTO subject_user_infos(#{column_value}) VALUES #{str.join(",")}"
# ActiveRecord::Base.connection.execute sql
# str = []
# end
end
if str.size > 0
sql = "REPLACE INTO subject_user_infos(#{column_value}) VALUES #{str.join(",")}"
puts sql
ActiveRecord::Base.connection.execute sql
buffer_size += 1
if buffer_size == 1000 || (index+1 == data.size)
sql = "REPLACE INTO subject_user_infos(#{column_value}) VALUES #{str}"
ActiveRecord::Base.connection.execute sql
str = ""
buffer_size = 0
end
end
end
end

@ -0,0 +1 @@
GENERATE_SOURCEMAP=false

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

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

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

@ -0,0 +1,83 @@
const {
override,
addLessLoader,
disableEsLint,
addBundleVisualizer,
addWebpackAlias,
fixBabelImports,
addWebpackPlugin
} = require("customize-cra")
const path = require('path');
const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin')
const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin')
const HardSourceWebpackPlugin = require('hard-source-webpack-plugin')
let instance = new HardSourceWebpackPlugin({
// Either an absolute path or relative to webpack's options.context.
cacheDirectory: 'node_modules/.cache/hard-source/[confighash]',
// Either a string of object hash function given a webpack config.
configHash: function (webpackConfig) {
// node-object-hash on npm can be used to build this.
return require('node-object-hash')({ sort: false }).hash(webpackConfig);
},
// Either false, a string, an object, or a project hashing function.
environmentHash: {
root: process.cwd(),
directories: [],
files: ['package-lock.json', 'yarn.lock'],
},// How to launch the extra processes. Default:
fork: (fork, compiler, webpackBin) => fork(
webpackBin(),
['--config', __filename], {
silent: true,
}
),
// Number of workers to spawn. Default:
numWorkers: () => require('os').cpus().length,
// Number of modules built before launching parallel building. Default:
minModules: 10,
// An object.
info: {
// 'none' or 'test'.
mode: 'none',
// 'debug', 'log', 'info', 'warn', or 'error'.
level: 'debug',
},
// Clean up large, old caches automatically.
cachePrune: {
// Caches younger than `maxAge` are not considered for deletion. They must
// be at least this (default: 2 days) old in milliseconds.
maxAge: 2 * 24 * 60 * 60 * 1000,
// All caches together must be larger than `sizeThreshold` before any
// caches will be deleted. Together they must be at least this
// (default: 50 MB) big in bytes.
sizeThreshold: 50 * 1024 * 1024
},
})
module.exports = override(
disableEsLint(),
// addBundleVisualizer(),
addWebpackAlias({
"educoder": path.resolve(__dirname, 'src/common/educoder.js')
}),
addLessLoader({
javascriptEnabled: true
}),
fixBabelImports('import', {
libraryName: 'antd',
libraryDirectory: 'es',
style: true
}),
addWebpackPlugin(new MonacoWebpackPlugin({})),
// addWebpackPlugin(instance),
(config) => {
config.resolve.plugins = config.resolve.plugins.filter(plugin => !(plugin instanceof ModuleScopePlugin));
if (process.env.NODE_ENV !== "development") {
config.output.publicPath = `/react/build/`;
}
return config
}
);

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

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

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

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

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

@ -9,7 +9,7 @@ const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin');
const WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin');
const eslintFormatter = require('react-dev-utils/eslintFormatter');
const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');
// const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin');
const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin');
const getClientEnvironment = require('./env');
const paths = require('./paths');
@ -30,9 +30,9 @@ const env = getClientEnvironment(publicUrl);
module.exports = {
// You may want 'eval' instead if you prefer to see the compiled output in DevTools.
// See the discussion in https://github.com/facebookincubator/create-react-app/issues/343.s
//devtool: "cheap-module-eval-source-map",
devtool: "cheap-module-eval-source-map",
// 开启调试
devtool: "source-map", // 开启调试
//devtool: "source-map", // 开启调试
// These are the "entry points" to our application.
// This means they will be the "root" imports that are included in JS bundle.
// The first two entry points enable "hot" CSS and auto-refreshes for JS.
@ -267,7 +267,7 @@ module.exports = {
// https://github.com/jmblog/how-to-optimize-momentjs-with-webpack
// You can remove this if you don't use Moment.js:
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
// new MonacoWebpackPlugin(),
new MonacoWebpackPlugin(),
],
// Some libraries import Node modules but don't use them in the browser.
// Tell Webpack to provide empty mocks for them so importing them works.

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

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

File diff suppressed because it is too large Load Diff

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

File diff suppressed because it is too large Load Diff

@ -859,8 +859,12 @@
content: "\e678";
}
.icon-VPN:before {
content: "\e601";
.icon-guolvqi:before {
content: "\e71b";
}
.icon-congshulianjie:before {
content: "\e6ee";
}
.icon-jquery:before {
@ -1359,3 +1363,10 @@
content: "\e640";
}
.icon-chushihua:before {
content: "\e71c";
}
.icon-ceshiji:before {
content: "\e71e";
}

File diff suppressed because one or more lines are too long

@ -1476,11 +1476,18 @@
"unicode_decimal": 59237
},
{
"icon_id": "1881547",
"name": "大数据存储",
"font_class": "dashujucunchu",
"unicode": "e678",
"unicode_decimal": 59000
"icon_id": "5327531",
"name": "过滤器",
"font_class": "guolvqi",
"unicode": "e71b",
"unicode_decimal": 59163
},
{
"icon_id": "5379378",
"name": "20从属连接",
"font_class": "congshulianjie",
"unicode": "e6ee",
"unicode_decimal": 59118
},
{
"icon_id": "2584358",
@ -2351,11 +2358,25 @@
"unicode_decimal": 58967
},
{
"icon_id": "4187234",
"name": "文件夹",
"font_class": "wenjianjia",
"unicode": "e640",
"unicode_decimal": 58944
"icon_id": "12621396",
"name": "加上2",
"font_class": "jiashang1",
"unicode": "e719",
"unicode_decimal": 59161
},
{
"icon_id": "12826208",
"name": "初始化",
"font_class": "chushihua",
"unicode": "e71c",
"unicode_decimal": 59164
},
{
"icon_id": "12826211",
"name": "测试集",
"font_class": "ceshiji",
"unicode": "e71e",
"unicode_decimal": 59166
}
]
}

@ -614,7 +614,10 @@ Created by iconfont
<glyph glyph-name="reset" unicode="&#59390;" d="M256 384H170.666667c0-185.002667 156.288-341.333333 341.333333-341.333333s341.333333 156.330667 341.333333 341.333333-156.288 341.333333-341.333333 341.333333V810.666667L342.4 682.666667 512 554.666667V640c138.752 0 256-117.248 256-256s-117.248-256-256-256-256 117.248-256 256zM640 384c0 71.210667-56.704 128-128 128s-128-56.789333-128-128 56.704-128 128-128 128 56.789333 128 128z" horiz-adv-x="1024" />
<glyph glyph-name="zhongzhi1" unicode="&#58889;" d="M511.99872 892.544C229.93792 892.544 1.28 664.86016 1.28 384.00256 1.28 103.13984 229.93792-124.544 511.99872-124.544 794.06592-124.544 1022.72 103.13984 1022.72 384.00256 1022.72 664.86016 794.06592 892.544 511.99872 892.544L511.99872 892.544zM520.3072 23.71968c-188.20096 0-341.3312 152.47616-341.3312 339.87584 0 187.3984 153.13024 339.87456 341.3312 339.87456l0.02816 0L520.33536 777.35552l178.08384-118.21696-178.08384-118.21952L520.33536 614.8096l-0.02816 0c-139.10784 0-252.28544-112.69376-252.28544-251.21536 0-138.5152 113.1776-251.21152 252.28544-251.21152s252.28672 112.69632 252.28672 251.21152c0 24.50432 19.91168 44.33152 44.52224 44.33152 24.60928 0 44.52224-19.8272 44.52224-44.33152C861.63712 176.19584 708.50304 23.71968 520.3072 23.71968L520.3072 23.71968zM520.3072 23.71968" horiz-adv-x="1024" />
<glyph glyph-name="guolvqi" unicode="&#59163;" d="M908.6 761.3c6.5-15.5 3.8-28.8-8-39.7L620.9 441.9V21c0-15.8-7.4-27.1-22.1-33.5-4.9-2-9.7-2.9-14.2-2.9-10.3 0-18.7 3.6-25.5 10.7L413.8 140.8c-7.2 7.2-10.7 15.7-10.7 25.5V441.9L123.4 721.6c-11.7 11-14.3 24.2-8 39.7 6.5 14.8 17.5 22.1 33.5 22.1H875c16 0.1 27.2-7.3 33.6-22.1z" horiz-adv-x="1024" />
<glyph glyph-name="congshulianjie" unicode="&#59118;" d="M844.8 230.4a128 128 0 0 1-125.44-102.4H358.4a102.4 102.4 0 0 0 0 204.8h307.2a153.6 153.6 0 0 1 0 307.2H304.64a128 128 0 1 1 0-51.2H665.6a102.4 102.4 0 0 0 0-204.8H358.4a153.6 153.6 0 0 1 0-307.2h360.96a128 128 0 1 1 125.44 153.6z m0-204.8a76.8 76.8 0 1 0 76.8 76.8 76.8 76.8 0 0 0-76.8-76.8z" horiz-adv-x="1024" />
<glyph glyph-name="default" unicode="&#59007;" d="M512.020 822.323c-239.75 0-434.093-195.721-434.093-437.159s194.342-437.159 434.093-437.159 434.112 195.721 434.112 437.159-194.362 437.159-434.112 437.159zM729.087 372.55c0-18.589-14.961-33.649-33.397-33.649h-367.321c-18.434 0-33.377 15.058-33.377 33.649v33.61c0 18.59 14.941 33.649 33.377 33.649h367.321c18.435 0 33.397-15.058 33.397-33.649v-33.61z" horiz-adv-x="1024" />
@ -1028,6 +1031,12 @@ Created by iconfont
<glyph glyph-name="wenjianjia" unicode="&#58944;" d="M957.3 464.4v56.7c0 57.8-47 104.8-104.8 104.8H510.1v46.8c0 57.8-47 104.8-104.8 104.8H172.6c-57.8 0-104.8-47-104.8-104.8v-208.3h889.5zM67.8 394.8v-304.5c0-57.8 47-104.8 104.8-104.8h680c57.8 0 104.8 47 104.8 104.8V394.8H67.8z" horiz-adv-x="1024" />
<glyph glyph-name="chushihua" unicode="&#59164;" d="M511.682434-128A468.457376 468.457376 0 0 0 44.559694 340.457376a66.73182 66.73182 0 0 0 133.46364 0A333.6591 333.6591 0 1 1 511.682434 675.451113a330.989827 330.989827 0 0 1-235.785764-98.095776 66.73182 66.73182 0 0 0-111.2197 66.73182l60.503517 203.309612a66.798552 66.798552 0 1 0 128.125094-37.814698l-9.564894-31.808835A468.234937 468.234937 0 1 0 511.682434-128zM600.658194 183.41516h-133.46364a66.73182 66.73182 0 0 0-66.73182 66.73182V472.58638a66.73182 66.73182 0 0 0 133.46364 0v-155.70758h66.73182a66.73182 66.73182 0 0 0 0-133.46364z" horiz-adv-x="1024" />
<glyph glyph-name="ceshiji" unicode="&#59166;" d="M536.332172 333.97898a75.330291 75.330291 0 0 0-29.985844 6.338471l-463.195967 207.95061a73.136205 73.136205 0 0 0 0 133.351681l463.195967 207.95061a73.136205 73.136205 0 0 0 59.971688 0l463.195966-207.95061a73.136205 73.136205 0 0 0 0-133.351681l-463.195966-207.95061a75.330291 75.330291 0 0 0-29.985844-6.338471zM251.832333 614.822008L536.332172 487.321224l284.499838 127.500784L536.332172 742.56658zM536.332172 102.868571a73.136205 73.136205 0 0 0-31.204781 7.069834l-463.195967 219.408615a73.184963 73.184963 0 0 0 62.409562 132.376532L536.332172 257.429752l431.259823 215.020443a73.136205 73.136205 0 0 0 65.33501-130.913807l-463.195966-230.866621a73.136205 73.136205 0 0 0-33.398867-7.801196zM536.332172-127.99805a73.136205 73.136205 0 0 0-31.204781 7.069833l-463.195967 219.408616a73.136205 73.136205 0 0 0 62.409562 131.888957L536.332172 26.319343l431.259823 215.264231a73.136205 73.136205 0 0 0 65.33501-130.913807l-463.195966-230.866621A73.136205 73.136205 0 0 0 536.332172-127.99805z" horiz-adv-x="1073" />
</font>

Before

Width:  |  Height:  |  Size: 410 KiB

After

Width:  |  Height:  |  Size: 412 KiB

@ -2,12 +2,7 @@
<html lang="en">
<head>
<meta charset="utf-8">
<!--<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">-->
<!-- width=device-width, initial-scale=1 , shrink-to-fit=no -->
<!-- <meta name="viewport" content=""> -->
<meta name=”Keywords” Content=”EduCoder,信息技术实践教学,精品课程网,慕课MOOC″>
<meta name=”Keywords” Content=”实践课程,项目实战,java实训,python实战,人工智能技术,后端开发学习,移动开发入门″>
<meta name=”Keywords” Content=”翻转课堂,高效课堂创建,教学模式″>
@ -21,30 +16,13 @@
Content=”EduCoder翻转课堂教学模式颠覆了传统教学模式让教师与学生的关系由“权威”变成了“伙伴”。将学习的主动权转交给学生使学生可个性化化学学生的学习主体得到了彰显。”>
<meta name=”Description” Content=”EduCoder实训项目为单个知识点关卡实践训练帮助学生巩固单一弱点强化学习。 >
<meta name=”Description” Content=”EduCoder实践教学平台各类大赛为进一步提高各类学生综合运用高级语言程序设计能力培养创新意识和实践探索精神发掘优秀软件人才。 >
<!-- <meta name="viewport" id="viewport" content="width=device-width, initial-scale=0.3, maximum-scale=0.3, user-scalable=no">-->
<!-- <meta name="viewport" id="viewport" content="width=device-width, initial-scale=0.3, maximum-scale=0.3">-->
<meta name="viewport" id="viewport" content="width=device-width, initial-scale=0.3, maximum-scale=0.3">
<meta name="theme-color" content="#000000">
<!--<meta http-equiv="cache-control" content="no-cache,no-store, must-revalidate" />-->
<!--<meta http-equiv="pragma" content="no-cache" />-->
<!--<meta http-equiv="Expires" content="0" />-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<!-- <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">-->
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<!-- <title>EduCoder</title>-->
<!--react-ssr-head-->
<script type="text/javascript">
window.__isR = true;
// 不支持ie9 ie10
if (
@ -52,60 +30,15 @@
|| navigator.userAgent.indexOf('MSIE 10') != -1)
&&
location.pathname.indexOf("/compatibility") == -1) {
debugger;
// location.href = './compatibility'
location.href = '/compatibility.html'
}
// const isMobile = (/android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(navigator.userAgent.toLowerCase()));
const isWeiXin = (/MicroMessenger/i.test(navigator.userAgent.toLowerCase()));
if (isWeiXin) {
document.write('<script type="text/javascript" src="/javascripts/wx/jweixin-1.3.0.js"><\/script>');
}
</script>
<!-- <link rel="stylesheet" type="text/css" href="/css/edu-common.css">
<link rel="stylesheet" type="text/css" href="/css/edu-public.css">
<link rel="stylesheet" type="text/css" href="/css/taskstyle.css">
<link rel="stylesheet" type="text/css" href="/css/font-awesome.css">
<link rel="stylesheet" type="text/css" href="/css/editormd.min.css">
<link rel="stylesheet" type="text/css" href="/css/merge.css"> -->
<link rel="stylesheet" type="text/css" href="/css/css_min_all.css">
<!--<link rel="stylesheet" type="text/css" href="/css/css_min_all.css">-->
<!--<link rel="stylesheet" type="text/css" href="//at.alicdn.com/t/font_653600_nm6lho7nxxq.css">-->
<!-- <link href="/react/build/css/iconfont.css" rel="stylesheet" type="text/css"> -->
<!--<link href="http://47.96.87.25:48080/stylesheets/educoder/edu-all.css" rel="stylesheet" type="text/css">-->
<!--<link href="https://pandao.github.io/editor.md/examples/css/style.css" rel="stylesheet" type="text/css">-->
<!--<link href="https://pandao.github.io/editor.md/css/editormd.preview.css" rel="stylesheet" type="text/css">-->
<!-- <link href="https://testeduplus2.educoder.net/stylesheets/css/edu-common.css" rel="stylesheet" type="text/css">
<link href="https://testeduplus2.educoder.net/stylesheets/educoder/edu-main.css" rel="stylesheet" type="text/css">
<link href="https://testeduplus2.educoder.net/stylesheets/educoder/antd.min.css" rel="stylesheet" type="text/css"> -->
<!-- <link rel="stylesheet" type="text/css" href="https://www.educoder.net/stylesheets/css/font-awesome.css?1510652321"> -->
<!--<link rel="stylesheet" type="text/css" href="http://47.96.87.25:48080/stylesheets/educoder/iconfont/iconfont.css">-->
<!--需要去build js配置-->
<link rel="stylesheet" type="text/css" href="/css/iconfont.css">
<link rel="stylesheet" type="text/css" href="%PUBLIC_URL%/css/css_min_all.css">
<link rel="stylesheet" type="text/css" href="%PUBLIC_URL%/css/iconfont.css">
<link rel="stylesheet" type="text/css" href="https://cdn.bootcss.com/quill/1.3.7/quill.core.min.css">
<style>
/*<!--去除浏览器点击操作后有蓝色的底块-->*/
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
</style>
</head>
@ -115,73 +48,12 @@
</noscript>
<!--用于markdown转html -->
<div id="md_div" style="display: none;"></div>
<div id="root" class="page -layout-v -fit widthunit">
<!--<div class="d2-home">-->
<!--<div class="d2-home__main">-->
<!--&lt;!&ndash;<img class="d2-home__loading"&ndash;&gt;-->
<!--&lt;!&ndash;src="loading-spin.svg"&ndash;&gt;-->
<!--&lt;!&ndash;alt="loading">&ndash;&gt;-->
<!--<div class="lds-ripple"><div></div><div></div></div>-->
<!--<div class="d2-home__title">-->
<!--正在加载资源-->
<!--</div>-->
<!--<div class="d2-home__sub-title">-->
<!--加载资源可能需要较多时间 请耐心等待-->
<!--</div>-->
<!--</div>-->
<!--<div class="d2-home__footer">-->
<!--&lt;!&ndash;<a href="www.educoder.net"&ndash;&gt;-->
<!--&lt;!&ndash;target="_blank">&ndash;&gt;-->
<!--&lt;!&ndash;&ndash;&gt;-->
<!--&lt;!&ndash;</a>&ndash;&gt;-->
<!--EduCoder-->
<!--</div>-->
<!--</div>-->
</div>
<div id="root" class="page -layout-v -fit widthunit"></div>
<div id="picture_display" style="display: none;"></div>
<!-- js css合并 文件优先级的问题 -->
<script type="text/javascript" src="/js/js_min_all.js"></script>
<script type="text/javascript" src="/js/flv.min.js"></script>
<!-- 在tpi js里加载这3个脚本 -->
<script>
(function () { // Scoping function to avoid globals
var href = location.href;
if (window.location.port === "3007") {
if (href.indexOf('/tasks/') != -1) {
document.write('<script type="text/javascript" src="https://newweb.educoder.net/assets/kindeditor/kindeditor.js"><\/script>');
// build.js中会将这个url附加一个前缀 react/build
document.write('<script type="text/javascript" src="/js/create_kindeditor.js"><\/script>');
document.write('<script type="text/javascript" src="https://newweb.educoder.net/javascripts/educoder/edu_application.js"><\/script>');
} else if (href.indexOf('/paths/') != -1) {
document.write('<script type="text/javascript" src="https://newweb.educoder.net/javascripts/educoder/edu_application.js"><\/script>');
}
} else {
if (href.indexOf('/tasks/') != -1) {
document.write('<script type="text/javascript" src="/assets/kindeditor/kindeditor.js"><\/script>');
// build.js中会将这个url附加一个前缀 react/build
document.write('<script type="text/javascript" src="/js/create_kindeditor.js"><\/script>');
document.write('<script type="text/javascript" src="/javascripts/educoder/edu_application.js"><\/script>');
} else if (href.indexOf('/paths/') != -1) {
document.write('<script type="text/javascript" src="/javascripts/educoder/edu_application.js"><\/script>');
}
}
})();
</script>
<!-- <script type="text/javascript" src="https://testeduplus2.educoder.net/assets/kindeditor/kindeditor.js"></script>
<script type="text/javascript" src="/js/create_kindeditor.js"></script>
<script type="text/javascript" src="https://testeduplus2.educoder.net/javascripts/educoder/edu_application.js"></script> -->
<script type="text/javascript" src="%PUBLIC_URL%/js/js_min_all.js"></script>
<script type="text/javascript" src="%PUBLIC_URL%/js/flv.min.js"></script>
<script type="text/javascript" src="https://cdn.bootcss.com/quill/1.3.7/quill.core.min.js"></script>
<!-- <script>-->
<!-- document.body.addEventListener('touchmove', function (e) {-->
<!-- e.preventDefault(); //阻止默认的处理方式(阻止下拉滑动的效果)-->
<!-- }, {passive: false});-->
<!-- </script>-->
</body>
</html>

@ -313,16 +313,10 @@ $(function(){
window.top.__updateWebsshRows && window.top.__updateWebsshRows(rows)
}
window.refresh_editor_monaco = function(height) {
console.log('refresh_editor_monaco')
if (window.editor_monaco) {
height && $('#codetab_con_1').height(height)
window.editor_monaco.layout();
}
// if ($('#game_operate_action').width() < 720) {
// $('#game_operate_action .time_limit').hide()
// } else {
// $('#game_operate_action .time_limit').show()
// }
}
// end;
//解決IE瀏覽器大小改變時webssh佈局變亂。

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

@ -228,6 +228,7 @@ function generateNewIndexJsp() {
// ${cdnHost} 加了cdn后这个文件里的字体文件加载会有跨域的报错 ../fonts/fontawesome-webfont.eot
// TODO tpi 评测结果关闭也使用了fontawesome
.replace(flvMinAllRegex,``)
.replace('/css/css_min_all.css', `${cdnHost}/react/build/css/css_min_all.css?v=${newVersion}`)
.replace('/css/iconfont.css', `${cdnHost}/react/build/css/iconfont.css?v=${newVersion}`)
.replace(/\/js\/create_kindeditor.js/g, `${cdnHost}/react/build/js/create_kindeditor.js?v=${newVersion}`)

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

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

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

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

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

@ -1,17 +1,13 @@
import React, { Component } from 'react';
import './public-path';
import './App.css';
import { ConfigProvider } from 'antd'
import zhCN from 'antd/lib/locale-provider/zh_CN';
import { ConfigProvider } from 'antd'
import {
BrowserRouter as Router,
Route,
Switch
} from 'react-router-dom';
import axios from 'axios';
import '@icedesign/base/dist/ICEDesignBase.css';
import '@icedesign/base/index.scss';
import LoginDialog from './modules/login/LoginDialog';
import Notcompletedysl from './modules/user/Notcompletedysl';
@ -21,42 +17,18 @@ import Addcourses from "./modules/courses/coursesPublic/Addcourses";
import AccountProfile from "./modules/user/AccountProfile";
import Accountnewprofile from './modules/user/Accountnewprofile';
import Certifiedprofessional from './modules/modals/Certifiedprofessional';
import Loading from './Loading'
import Loadable from 'react-loadable';
import moment from 'moment'
import { MuiThemeProvider, createMuiTheme } from 'material-ui/styles';
// import './AppConfig'
import history from './history';
import { SnackbarHOC } from 'educoder'
import { SnackbarHOC,Loadable } from 'educoder'
import { initAxiosInterceptors } from './AppConfig'
import { Provider } from 'react-redux';
import configureStore from './redux/stores/configureStore';
// tpi需要这个来加载css
import { TPMIndexHOC } from './modules/tpm/TPMIndexHOC';
const store = configureStore();
const theme = createMuiTheme({
palette: {
primary: {
main: '#4CACFF',
contrastText: 'rgba(255, 255, 255, 0.87)'
},
secondary: { main: '#4CACFF' }, // #11cb5f This is just green.A700 as hex.
},
});
//
// const Trialapplication= Loadable({
// loader: () =>import('./modules/login/Trialapplication'),
// loading:Loading,
// })
//登入
const EducoderLogin = Loadable({
loader: () => import('./modules/login/EducoderLogin'),
@ -85,10 +57,6 @@ const Otherloginsqq = Loadable({
loader: () => import('./modules/login/Otherloginqq'),
loading: Loading,
})
// const TestIndex = Loadable({
// loader: () => import('./modules/test'),
// loading: Loading,
// })
const IndexWrapperComponent = Loadable({
loader: () => import('./modules/page/IndexWrapper'),
@ -125,49 +93,12 @@ const SearchPage = Loadable({
loading: Loading,
})
// 课堂讨论
// const BoardIndex = Loadable({
// loader: () => import('./modules/courses/boards/BoardIndex'),
// loading:Loading,
// })
// //课堂普通作业&分组作业
// const CoursesWorkIndex = Loadable({
// loader: () => import('./modules/courses/busyWork/Index'),
// loading:Loading,
// })
//
// const TPMShixunchildIndexComponent = Loadable({
// loader: () => import('./modules/tpm/shixunchild/ShixunChildIndex'),
// loading: Loading,
// })
// const TPMshixunfork_listIndexComponent = Loadable({
// loader: () => import('./modules/tpm/shixunchild/Shixunfork_list'),
// loading: Loading,
// })
const ForumsIndexComponent = Loadable({
loader: () => import('./modules/forums/ForumsIndex'),
loading: Loading,
})
// trustie plus forum
// const TPForumsIndexComponent = Loadable({
// loader: () => import('./modules/tp-forums/TPForumsIndex'),
// loading: Loading,
// })
// const TestPageComponent = Loadable({
// loader: () => import('./modules/page/Index'),
// loading: Loading,
// })
//新建实训
const Newshixuns = Loadable({
loader: () => import('./modules/tpm/newshixuns/Newshixuns'),
@ -177,7 +108,7 @@ const Newshixuns = Loadable({
//实训首页
const ShixunsHome = Loadable({
loader: () => import('./modules/home/shixunsHome'),
loader: () => import('./modules/home'),
loading: Loading,
})
@ -206,21 +137,11 @@ const http500 = Loadable({
loading: Loading,
})
// 登录注册
const LoginRegisterPage = Loadable({
loader: () => import('./modules/user/LoginRegisterPage'),
loading: Loading,
})
const AccountPage = Loadable({
loader: () => import('./modules/user/AccountPage'),
loading: Loading,
})
// 个人主页
const UsersInfo = Loadable({
loader: () => import('./modules/user/usersInfo/Infos'),
loading: Loading,
})
const InfosIndex = Loadable({
loader: () => import('./modules/user/usersInfo/InfosIndex'),
loading: Loading,
@ -238,17 +159,6 @@ const MoopCases = Loadable({
loading: Loading,
})
// 兴趣页面
const Interestpage = Loadable({
loader: () => import('./modules/login/EducoderInteresse'),
loading: Loading,
})
//众包创新
// const ProjectPackages=Loadable({
// loader: () => import('./modules/projectPackages/ProjectPackageIndex'),
// loading: Loading,
// })
//竞赛
const NewCompetitions = Loadable({
@ -352,16 +262,6 @@ const JupyterTPI = Loadable({
loader: () => import('./modules/tpm/jupyter'),
loading: Loading
});
// 微信代码编辑器
// const WXCode = Loadable({
// loader: () => import('./modules/wxcode'),
// loading: Loading
// });
// //个人竞赛报名
// const PersonalCompetit = Loadable({
// loader: () => import('./modules/competition/personal/PersonalCompetit.js'),
// loading: Loading,
// });
class App extends Component {
constructor(props) {
super(props)
@ -422,20 +322,6 @@ class App extends Component {
initAxiosInterceptors(this.props);
this.getAppdata();
//
// axios.interceptors.response.use((response) => {
// // console.log("response"+response);
// if(response!=undefined)
// // console.log("response"+response.data.statu);
// if (response&&response.data.status === 407) {
// this.setState({
// isRenders: true,
// })
// }
// return response;
// }, (error) => {
// //TODO 这里如果样式变了会出现css不加载的情况
// });
window.addEventListener('error', (event) => {
const msg = `${event.type}: ${event.message}`;
@ -522,13 +408,10 @@ class App extends Component {
};
render() {
let { mygetHelmetapi } = this.state;
// console.log("appappapp");
// console.log(mygetHelmetapi);
return (
<Provider store={store}>
<ConfigProvider locale={zhCN}>
<MuiThemeProvider theme={theme}>
<Accountnewprofile {...this.props}{...this.state} />
<LoginDialog {...this.props} {...this.state} Modifyloginvalue={() => this.Modifyloginvalue()}></LoginDialog>
<Notcompletedysl {...this.props} {...this.state}></Notcompletedysl>
@ -596,19 +479,18 @@ class App extends Component {
render={
(props) => {
return (<EducoderLogin {...this.props} {...props} {...this.state} />)
}
}
/>
<Route
path="/register"
render={
(props) => {
return (<EducoderLogin {...this.props} {...props} {...this.state} />)
}
return (<Topicbank {...this.props} {...props} {...this.state} />)
}
/>
}></Route>
{/*/!*众包创新*!/*/}
{/*<Route path={"/crowdsourcing"} component={ProjectPackages}/>*/}
{/*竞赛*/}
<Route path={"/competitions"}
render={
(props) => {
return (<NewCompetitions {...this.props} {...props} {...this.state} />)
}} />
<Route
path="/otherloginstart" component={Otherloginstart}
/>
@ -822,9 +704,10 @@ class App extends Component {
</Switch>
</Router>
</MuiThemeProvider>
</ConfigProvider>
</Provider>
</Provider >
);
}
}

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

@ -139,7 +139,7 @@ export function initAxiosInterceptors(props) {
proxy = "https://test-newweb.educoder.net"
// proxy="https://test-jupyterweb.educoder.net"
// proxy="https://test-newweb.educoder.net"
// proxy="https://test-jupyterweb.educoder.net"
proxy="https://test-jupyterweb.educoder.net"
//proxy="https://test-jupyterweb.educoder.net/"

@ -1,12 +0,0 @@
import Loadable from 'react-loadable';
import Loading from "./Loading";
const CustomLoadable = (loader, loading = Loading) => {
return Loadable({
loader,
loading
})
}
export default CustomLoadable

@ -1,21 +1,9 @@
import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
import { Spin } from 'antd';
class Loading extends Component {
componentDidUpdate(prevProps, prevState) {
if (!prevProps.error && this.props.error) {
console.log(this.props.error)
window.location.reload()
}
}
render() {
// Loading
return (
<div className="App" style={{minHeight: '800px',width:"100%"}}>
render() {
return (
<div className="App" style={{ minHeight: '800px', width: "100%" }}>
<style>
{
`
@ -25,10 +13,10 @@ class Loading extends Component {
`
}
</style>
<Spin size="large" className={"margintop"}/>
</div>
);
}
<p>loading...</p>
</div>
);
}
}
export default Loading;

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

@ -1,20 +1,17 @@
import React, {Component} from "react";
import {Link, NavLink} from 'react-router-dom';
import {WordsBtn, ActionBtn,SnackbarHOC,getImageUrl} from 'educoder';
import axios from 'axios';
import React, {Component} from "react"
import {SnackbarHOC,getImageUrl} from 'educoder'
import axios from 'axios'
import {
notification,
Spin,
Table,
Pagination,
} from "antd";
} from "antd"
import Colleagechart from './colleagechart/Colleagechart'
import Colleagechartzu from './colleagechart/Colleagechartzu'
import {TPMIndexHOC} from "../modules/tpm/TPMIndexHOC";
import NoneData from './../modules/courses/coursesPublic/NoneData';
import TPMIndexHOC from "../modules/tpm/TPMIndexHOC"
import NoneData from './../modules/courses/coursesPublic/NoneData'
import './colleagecss/colleage.css';
import Shixunechart from "../modules/courses/shixunHomework/shixunreport/Shixunechart";
class College extends Component {
constructor(props) {
super(props);
@ -1199,24 +1196,10 @@ class College extends Component {
className="mysjysltable1"
pagination={false}
loading={studentsloading}
// onChange={this.TablePaginationsy}
/>}
</div>
</div>
}
{/*<div style={{*/}
{/* width:'100%',*/}
{/* padding:'40px'*/}
{/*}}>*/}
{/* <div className="edu-txt-center ">*/}
{/* <Pagination showQuickJumper current={pagess} onChange={this.paginationonChangess}*/}
{/* pageSize={limitss}*/}
{/* total={student_count}></Pagination>*/}
{/* </div>*/}
{/*</div>*/}
</div>
<div className="" style={{
@ -1259,3 +1242,4 @@ class College extends Component {
export default SnackbarHOC() (TPMIndexHOC ( College ));

@ -1,5 +1,5 @@
import md5 from 'md5';
export function setmiyah(logins){
const opens ="79e33abd4b6588941ab7622aed1e67e8";
return md5(opens+logins);
export default function setmiyah(logins) {
const opens = "79e33abd4b6588941ab7622aed1e67e8";
return md5(opens + logins);
}

@ -4,7 +4,7 @@ export function trigger(eventName, data) {
}
export function on(eventName, callback) {
$(window).on(eventName, (event, data)=>{
$(window).on(eventName, (event, data) => {
callback && callback(event, data)
});
}
@ -25,7 +25,7 @@ function onMessageByLocalStorage(eventName, callback) {
console.log('storage event register:', eventName)
localStorageMap[eventName] = callback;
}
window.addEventListener("storage", function(ev) {
window.addEventListener("storage", function (ev) {
const cb = localStorageMap[ev.key];
// console.log('storage event:', ev)
if (cb) {
@ -59,12 +59,11 @@ export function broadcastChannelOnmessage(eventName, callback) {
var bc;
if (!broadcastChannelMap[eventName]) {
bc = new window.BroadcastChannel(eventName);
broadcastChannelMap[eventName] = bc
broadcastChannelMap[eventName] = bc
} else {
bc = broadcastChannelMap[eventName]
}
bc.onmessage = function (ev) {
console.log(ev);
bc.onmessage = function (ev) {
callback && callback(ev)
}
}

@ -1,9 +1,9 @@
import React, { Component } from 'react';
import { SnackbarHOC } from 'educoder';
import { TPMIndexHOC } from '../modules/tpm/TPMIndexHOC';
import {Spin,Alert} from 'antd';
import TPMIndexHOC from '../modules/tpm/TPMIndexHOC';
import { Spin, Alert } from 'antd';
class ShowSpin extends Component{
class ShowSpin extends Component {
constructor(props) {
super(props)
}
@ -11,23 +11,23 @@ class ShowSpin extends Component{
render() {
let marigin={
let marigin = {
width: '100%',
minHeight: '500px',
}
return (
<Spin style={marigin}>
<Spin style={marigin}>
<Alert
style={marigin}
type="info"
/>
<Alert
style={marigin}
type="info"
/>
</Spin>
</Spin>
)
}
}
export default SnackbarHOC() ( TPMIndexHOC(ShowSpin) );
export default SnackbarHOC()(TPMIndexHOC(ShowSpin));

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

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

@ -1,63 +1,43 @@
import React from "react";
import md5 from 'md5';
import {Input} from "antd";
import { Input } from "antd";
const { Search } = Input;
const $ = window.$;
const isDev = window.location.port == 3007;
export const TEST_HOST = "https://test-newweb.educoder.net"
export function getImageUrl(path) {
// https://www.educoder.net
// https://testbdweb.trustie.net
// const local = 'http://localhost:3000'
const local = 'https://test-newweb.educoder.net'
const local = 'https://test-newweb.educoder.net'
if (isDev) {
return `${local}/${path}`
}
return `/${path}`;
}
export function setImagesUrl(path){
export function setImagesUrl(path) {
const local = 'https://test-newweb.educoder.net'
let firstStr=path.substr(0,1);
// console.log(firstStr);
if(firstStr=="/"){
return isDev?`${local}${path}`:`${path}`;
}else{
return isDev?`${local}/${path}`:`/${path}`;
let firstStr = path.substr(0, 1);
if (firstStr == "/") {
return isDev ? `${local}${path}` : `${path}`;
} else {
return isDev ? `${local}/${path}` : `/${path}`;
}
}
export function getUrl(path, goTest) {
// https://www.educoder.net
// https://testbdweb.trustie.net
// 如果想所有url定位到测试版可以反注释掉下面这行
//goTest = true
// testbdweb.educoder.net testbdweb.trustie.net
// const local = goTest ? 'https://testeduplus2.educoder.net' : 'http://localhost:3000'
// const local = 'https://testeduplus2.educoder.net'
export function getUrl(path) {
const local = 'https://test-newweb.educoder.net'
if (isDev) {
return `${local}${path?path:''}`
return `${local}${path ? path : ''}`
}
return `${path ? path: ''}`;
return `${path ? path : ''}`;
}
export function getUrlmys(path, goTest) {
// https://www.educoder.net
// https://testbdweb.trustie.net
// 如果想所有url定位到测试版可以反注释掉下面这行
//goTest = true
// testbdweb.educoder.net testbdweb.trustie.net
// const local = goTest ? 'https://testeduplus2.educoder.net' : 'http://localhost:3000'
// const local = 'https://testeduplus2.educoder.net'
const local = 'https://test-jupyterweb.educoder.net'
if (isDev) {
return `${local}${path?path:''}`
return `${local}${path ? path : ''}`
}
return `${path ? path: ''}`;
return `${path ? path : ''}`;
}
export function getStaticUrl() {
const local = TEST_HOST;
@ -68,27 +48,29 @@ export function getStaticUrl() {
return ''
}
export function getUrl2(path, goTest) {
const local = 'http://localhost:3000'
const local = 'http://localhost:3000'
if (isDev) {
return `${local}${path?path:''}`
return `${local}${path ? path : ''}`
}
return `${path ? path: ''}`;
return `${path ? path : ''}`;
}
const newopens ="79e33abd4b6588941ab7622aed1e67e8";
const newopens = "79e33abd4b6588941ab7622aed1e67e8";
let newtimestamp;
let checkSubmitFlgs = false;
function railsgettimess(proxy) {
if(checkSubmitFlgs===false){
$.ajax({url:proxy,
async:false,success:function(data){
if(data.status===0){
newtimestamp=data.message;
if (checkSubmitFlgs === false) {
$.ajax({
url: proxy,
async: false, success: function (data) {
if (data.status === 0) {
newtimestamp = data.message;
checkSubmitFlgs = true;
}
}})
}
})
window.setTimeout(function () {
checkSubmitFlgs=false;
checkSubmitFlgs = false;
}, 2500);
}
}
@ -107,19 +89,19 @@ export function getmyUrl(geturl) {
export function getUploadActionUrl(path, goTest) {
Railsgettimes()
let anewopens=md5(newopens+newtimestamp);
let anewopens = md5(newopens + newtimestamp);
return `${getUrl()}/api/attachments.json${isDev ? `?debug=${window._debugType || 'admin'}&randomcode=${newtimestamp}&client_key=${anewopens}` : `?randomcode=${newtimestamp}&client_key=${anewopens}`}`;
}
export function getUploadActionUrltwo(id) {
Railsgettimes()
let anewopens=md5(newopens+newtimestamp);
let anewopens = md5(newopens + newtimestamp);
return `${getUrlmys()}/api/shixuns/${id}/upload_data_sets.json${isDev ? `?debug=${window._debugType || 'admin'}&randomcode=${newtimestamp}&client_key=${anewopens}` : `?randomcode=${newtimestamp}&client_key=${anewopens}`}`
}
export function getUploadActionUrlthree() {
Railsgettimes()
let anewopens=md5(newopens+newtimestamp);
let anewopens = md5(newopens + newtimestamp);
return `${getUrlmys()}/api/jupyters/import_with_tpm.json${isDev ? `?debug=${window._debugType || 'admin'}&randomcode=${newtimestamp}&client_key=${anewopens}` : `?randomcode=${newtimestamp}&client_key=${anewopens}`}`
}
@ -132,14 +114,14 @@ export function getupload_git_file(id) {
export function getUploadActionUrlOfAuth(id) {
Railsgettimes()
let anewopens=md5(newopens+newtimestamp);
let anewopens = md5(newopens + newtimestamp);
return `${getUrl()}/api/users/accounts/${id}/auth_attachment.json${isDev ? `?debug=${window._debugType || 'admin'}&randomcode=${newtimestamp}&client_key=${anewopens}` : `?randomcode=${newtimestamp}&client_key=${anewopens}`}`
}
export function getRandomNumber(type) {
Railsgettimes()
let anewopens=md5(newopens+newtimestamp);
return type===true?`randomcode=${newtimestamp}&client_key=${anewopens}`:`?randomcode=${newtimestamp}&client_key=${anewopens}`
Railsgettimes()
let anewopens = md5(newopens + newtimestamp);
return type === true ? `randomcode=${newtimestamp}&client_key=${anewopens}` : `?randomcode=${newtimestamp}&client_key=${anewopens}`
}
export function test(path) {
@ -157,11 +139,11 @@ export function getTaskUrlById(id) {
export function getRandomcode(url) {
Railsgettimes()
let anewopens=md5(newopens+newtimestamp);
let anewopens = md5(newopens + newtimestamp);
if (url.indexOf('?') == -1) {
return `${url}?randomcode=${newtimestamp}&client_key=${anewopens}`
}else {
} else {
return `${url}&randomcode=${newtimestamp}&client_key=${anewopens}`
}
@ -181,14 +163,14 @@ export function htmlEncode(str) {
return s;
}
export function publicSearchs(Placeholder,onSearch,onInputs,onChanges,loadings) {
return(<Search
placeholder= { Placeholder || "请输入内容进行搜索" }
export function publicSearchs(Placeholder, onSearch, onInputs, onChanges, loadings) {
return (<Search
placeholder={Placeholder || "请输入内容进行搜索"}
onSearch={onSearch}
// value={searchValue}
onInput={onInputs}
onChange={onChanges}
loading={loadings||false}
loading={loadings || false}
allowClear={true}
></Search>)
}

@ -2,21 +2,21 @@ import React, { Component } from 'react';
import { Modal } from 'antd';
export function ModalHOC(options = {}) {
export default function ModalHOC(options = {}) {
return function wrap(WrappedComponent) {
return class Wrapper extends Component {
constructor(props) {
super(props);
this.state = {
titlemessage: '',
Modallist: false,
Modallisttype: false,
singleButton: false
}
}
// 全局的modal this.props.showModal 调用即可
return class Wrapper extends Component {
constructor(props) {
super(props);
this.state = {
titlemessage: '',
Modallist: false,
Modallisttype: false,
singleButton: false
}
}
// 全局的modal this.props.showModal 调用即可
showModal = (title, content, okCallback) => {
this.okCallback = okCallback;
this.setState({
@ -39,55 +39,55 @@ export function ModalHOC(options = {}) {
onCancel = () => {
this.setState({
Modallisttype:false
})
Modallisttype: false
})
}
hidemodeldelete = () => {
hidemodeldelete = () => {
if (this.okCallback) {
this.okCallback()
}
this.onCancel()
}
render() {
const { titlemessage, Modallisttype, Modallist, singleButton } = this.state;
return (
<React.Fragment>
<Modal
keyboard={false}
title={titlemessage}
// visible={modeldelet===true&&listid===list.id?true:false}
visible={Modallisttype}
className={"ecmodeldelet"}
closable={false}
footer={null}
>
<div className="task-popup-content" >
<div className="task-popup-text-center font-14">{Modallist}</div>
</div>
{ singleButton ? <div className="task-popup-submit clearfix"
style={{ textAlign: 'center' }}>
<a className="task-btn task-btn-orange"
onClick={this.onCancel}
>知道啦</a>
</div> : <div className="task-popup-submit clearfix">
<a onClick={this.onCancel} className="task-btn fl">取消</a>
<a className="task-btn task-btn-orange fr"
onClick={this.hidemodeldelete}
>确定</a>
</div> }
</Modal>
<WrappedComponent {...this.props}
showModal={ this.showModal }
showSingleButtonModal={ this.showSingleButtonModal }
>
</WrappedComponent>
</React.Fragment>
)
}
}
}
render() {
const { titlemessage, Modallisttype, Modallist, singleButton } = this.state;
return (
<React.Fragment>
<Modal
keyboard={false}
title={titlemessage}
// visible={modeldelet===true&&listid===list.id?true:false}
visible={Modallisttype}
className={"ecmodeldelet"}
closable={false}
footer={null}
>
<div className="task-popup-content" >
<div className="task-popup-text-center font-14">{Modallist}</div>
</div>
{singleButton ? <div className="task-popup-submit clearfix"
style={{ textAlign: 'center' }}>
<a className="task-btn task-btn-orange"
onClick={this.onCancel}
>知道啦</a>
</div> : <div className="task-popup-submit clearfix">
<a onClick={this.onCancel} className="task-btn fl">取消</a>
<a className="task-btn task-btn-orange fr"
onClick={this.hidemodeldelete}
>确定</a>
</div>}
</Modal>
<WrappedComponent {...this.props}
showModal={this.showModal}
showSingleButtonModal={this.showSingleButtonModal}
>
</WrappedComponent>
</React.Fragment>
)
}
}
}
}

@ -1,6 +1,6 @@
import React, { Component } from 'react';
import { Modal } from 'antd';
export function SetAppModel(options={}) {
export default function SetAppModel(options = {}) {
return function wrap(WrappedComponent) {
return class Wrapper extends Component {
constructor(props) {
@ -10,14 +10,14 @@ export function SetAppModel(options={}) {
}
}
modalCancel=()=>{
modalCancel = () => {
window.location.href = "/";
}
setDownload=()=>{
window.location.href ='/account/profile';
setDownload = () => {
window.location.href = '/account/profile';
}
componentDidMount(){
componentDidMount() {
console.log(this.props)
}
@ -38,8 +38,8 @@ export function SetAppModel(options={}) {
<div className={"tabeltext-alignleft mt10"}><p>您尚未完善个人资料</p></div>
<div className={"tabeltext-alignleft mt10"}><p>请在完成资料后提交试用申请</p></div>
<div className="clearfix mt30 edu-txt-center">
<a className="task-btn mr30" onClick={()=>this.modalCancel()}>取消</a>
<a className="task-btn task-btn-orange" onClick={()=>this.setDownload()}>立即完善资料</a>
<a className="task-btn mr30" onClick={() => this.modalCancel()}>取消</a>
<a className="task-btn task-btn-orange" onClick={() => this.setDownload()}>立即完善资料</a>
</div>
</div>
</Modal>

@ -6,7 +6,7 @@
* @LastEditors : tangjiang
* @LastEditTime : 2020-01-06 18:42:09
*/
import './index.scss';
import './index.less';
import React, { useState } from 'react';
import { Form, Button, Input } from 'antd';
import QuillForEditor from '../../quillForEditor';

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

@ -6,7 +6,7 @@
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-27 11:05:17
*/
import './index.scss';
import './index.less';
import React, { useState } from 'react';
import CommentIcon from './CommentIcon';
import { getImageUrl, CNotificationHOC } from 'educoder'
@ -16,7 +16,6 @@ import QuillForEditor from '../../quillForEditor';
function CommentItem({
isAdmin,
options,
confirm,
comment,
submitDeleteComment,

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

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

@ -1,77 +1,82 @@
//import { from } from '_array-flatten@2.1.2@array-flatten';
// export { default as OrderStateUtil } from '../routes/Order/components/OrderStateUtil';
export {
getImageUrl as getImageUrl, getmyUrl as getmyUrl, getRandomNumber as getRandomNumber, getUrl as getUrl, publicSearchs as publicSearchs, getRandomcode as getRandomcode, getUrlmys as getUrlmys, getUrl2 as getUrl2, setImagesUrl as setImagesUrl
, getUploadActionUrl as getUploadActionUrl, getUploadActionUrltwo as getUploadActionUrltwo, getUploadActionUrlthree as getUploadActionUrlthree, getUploadActionUrlOfAuth as getUploadActionUrlOfAuth
, getTaskUrlById as getTaskUrlById, TEST_HOST, htmlEncode as htmlEncode, getupload_git_file as getupload_git_file
} from './UrlTool';
export { getImageUrl as getImageUrl,getmyUrl as getmyUrl, getRandomNumber as getRandomNumber,getUrl as getUrl, publicSearchs as publicSearchs,getRandomcode as getRandomcode,getUrlmys as getUrlmys, getUrl2 as getUrl2, setImagesUrl as setImagesUrl
, getUploadActionUrl as getUploadActionUrl,getUploadActionUrltwo as getUploadActionUrltwo ,getUploadActionUrlthree as getUploadActionUrlthree, getUploadActionUrlOfAuth as getUploadActionUrlOfAuth
, getTaskUrlById as getTaskUrlById, TEST_HOST ,htmlEncode as htmlEncode ,getupload_git_file as getupload_git_file} from './UrlTool';
export { default as setmiyah } from './Component';
export { default as queryString } from './UrlTool2';
export {setmiyah as setmiyah} from './Component';
export { default as queryString } from './UrlTool2';
export { default as SnackbarHOC } from './SnackbarHOC';
export { SnackbarHOC as SnackbarHOC } from './SnackbarHOC';
export {
trigger as trigger, on as on, off as off
, broadcastChannelPostMessage, broadcastChannelOnmessage
} from './EventUtil';
export { trigger as trigger, on as on, off as off
, broadcastChannelPostMessage, broadcastChannelOnmessage } from './EventUtil';
export { updatePageParams as updatePageParams } from './RouterUtil';
export { updatePageParams as updatePageParams } from './RouterUtil';
export { bytesToSize as bytesToSize } from './UnitUtil';
export { bytesToSize as bytesToSize } from './UnitUtil';
export { markdownToHTML, uploadNameSizeSeperator, appendFileSizeToUploadFile, appendFileSizeToUploadFileAll, isImageExtension,
downloadFile, sortDirections } from './TextUtil'
export { handleDateString, getNextHalfHourOfMoment,formatDuring,formatSeconds} from './DateUtil'
export { configShareForIndex, configShareForPaths, configShareForShixuns, configShareForCourses, configShareForCustom } from './util/ShareUtil'
export { isDev as isDev, isMobile } from './Env'
export { isDev as isDev, isMobile } from './Env'
export { toStore as toStore, fromStore as fromStore } from './Store'
export { toStore as toStore, fromStore as fromStore } from './Store'
export { trace_collapse, trace, debug, info, warn, error, trace_c, debug_c, info_c, warn_c, error_c } from './LogUtil'
export { trace_collapse, trace, debug, info, warn, error, trace_c, debug_c, info_c, warn_c, error_c } from './LogUtil'
export { EDU_ADMIN, EDU_BUSINESS, EDU_SHIXUN_MANAGER, EDU_SHIXUN_MEMBER, EDU_CERTIFICATION_TEACHER
, EDU_GAME_MANAGER, EDU_TEACHER, EDU_NORMAL} from './Const'
export {
EDU_ADMIN, EDU_BUSINESS, EDU_SHIXUN_MANAGER, EDU_SHIXUN_MEMBER, EDU_CERTIFICATION_TEACHER
, EDU_GAME_MANAGER, EDU_TEACHER, EDU_NORMAL
} from './Const'
export { default as AttachmentList } from './components/attachment/AttachmentList'
export { themes, ThemeContext } from './context/ThemeContext'
export { themes, ThemeContext } from './context/ThemeContext'
export { ModalHOC } from './components/ModalHOC'
export { default as ModalHOC } from './components/ModalHOC'
export { SetAppModel } from './components/SetAppModel'
export { default as SetAppModel } from './components/SetAppModel'
export { default as LinkAfterLogin } from './components/LinkAfterLogin'
export { default as Cropper } from './components/Cropper'
export { default as ConditionToolTip } from './components/ConditionToolTip'
export { default as LinkAfterLogin } from './components/LinkAfterLogin'
export { default as Cropper } from './components/Cropper'
export { default as ConditionToolTip } from './components/ConditionToolTip'
// export { default as DragValidator } from './components/DragValidator'
export { default as PopInstruction } from './components/instruction/PopInstruction'
export { configShareForIndex, configShareForPaths, configShareForShixuns, configShareForCourses, configShareForCustom } from './util/ShareUtil'
export { default as PopInstruction } from './components/instruction/PopInstruction'
export { default as City } from './components/form/City'
export { default as City } from './components/form/City'
// course
export { default as WordsBtn } from './course/WordsBtn'
export { default as WordsBtn } from './course/WordsBtn'
export { default as ActionBtn } from './course/ActionBtn'
export { default as MarkdownToHtml } from './components/markdown/MarkdownToHtml'
export { default as DMDEditor } from './components/markdown/DMDEditor'
export { default as Clappr } from './components/media/Clappr'
export { default as AliyunUploader } from './components/media/AliyunUploader'
export { default as ImageLayer2 } from './hooks/ImageLayer2'
// 外部
export { default as CBreadcrumb } from '../modules/courses/common/CBreadcrumb'
export { CNotificationHOC as CNotificationHOC } from '../modules/courses/common/CNotificationHOC'
export { default as CNotificationHOC } from '../modules/courses/common/CNotificationHOC'
export { default as ModalWrapper } from '../modules/courses/common/ModalWrapper'
export { default as NoneData } from '../modules/courses/coursesPublic/NoneData'
export {default as WordNumberTextarea} from '../modules/modals/WordNumberTextarea'
export { default as WordNumberTextarea } from '../modules/modals/WordNumberTextarea'
import loadable from '@loadable/component'
import defaultLoading from '../Loading'
export function Loadable({ loader, loading = defaultLoading }) {
return loadable(loader, {
fallback: loading
})
}

@ -6,7 +6,7 @@
* @LastEditors : tangjiang
* @LastEditTime : 2020-02-05 11:23:03
*/
import './index.scss';
import './index.less';
import 'quill/dist/quill.core.css'; // 核心样式
import 'quill/dist/quill.snow.css'; // 有工具栏
import 'quill/dist/quill.bubble.css'; // 无工具栏
@ -32,11 +32,9 @@ Quill.register(ImageBlot);
Quill.register(Size);
Quill.register(LinkBlot);
Quill.register(Font, true);
// Quill.register({'modules/toolbar': Toolbar});
Quill.register({
'formats/fill': FillBlot
});
// Quill.register(Color);
function QuillForEditor({

File diff suppressed because it is too large Load Diff

@ -0,0 +1,28 @@
import test from 'ava';
import asciimathToTex from './asciimath-to-tex';
test('just a number', t => {
t.is(asciimathToTex('5'), '{5}');
});
test('x=5', t => {
t.is(asciimathToTex('x=5'), '{x}={5}');
});
test('x=5+2', t => {
t.is(asciimathToTex('x=5+2'), '{x}={5}+{2}');
});
test('x = (-b+-sqrt(b^2-4ac))/(2a)', t => {
t.is(
asciimathToTex('x = (-b+-sqrt(b^2-4ac))/(2a)'),
'{x}=\\frac{{-{b}\\pm\\sqrt{{{b}^{{2}}-{4}{a}{c}}}}}{{{2}{a}}}',
);
});
test('{x}=(-b+-sqrt(b^2-4ac))/(2a)', t => {
t.is(
asciimathToTex('{x}=(-b+-sqrt(b^2-4ac))/(2a)'),
'{\\left\\lbrace{x}\\right\\rbrace}=\\frac{{-{b}\\pm\\sqrt{{{b}^{{2}}-{4}{a}{c}}}}}{{{2}{a}}}',
);
});

@ -0,0 +1,121 @@
import katex from 'katex';
import renderMathInElement from 'katex/dist/contrib/auto-render';
import showdown from 'showdown';
import asciimathToTex from './asciimath-to-tex';
if (process.env.TARGET === 'cjs') {
const { JSDOM } = require('jsdom');
const jsdom = new JSDOM();
global.DOMParser = jsdom.window.DOMParser;
global.document = jsdom.window.document;
}
/**
* @param {object} opts
* @param {NodeListOf<Element>} opts.elements
* @param opts.config
* @param {boolean} opts.isAsciimath
*/
function renderBlockElements({ elements, config, isAsciimath }) {
if (!elements.length) {
return;
}
elements.forEach(element => {
const input = element.textContent || element.innerText;
const latex = isAsciimath ? asciimathToTex(input) : input;
const html = katex.renderToString(latex, config);
element.parentNode.outerHTML = `<span title="${input.trim()}">${html}</span>`;
});
}
/**
* https://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex
* @param {string} str
* @returns {string} regexp escaped string
*/
function escapeRegExp(str) {
return str.replace(/[-[\]/{}()*+?.\\$^|]/g, '\\$&');
}
// katex config
const getConfig = (config = {}) => ({
displayMode: true,
throwOnError: false, // fail silently
errorColor: '#ff0000',
...config,
delimiters: [
{ left: '$$', right: '$$', display: false, asciimath: false },
{ left: '~', right: '~', display: false, asciimath: true },
].concat(config.delimiters || []),
});
const showdownKatex = userConfig => () => {
const parser = new DOMParser();
const config = getConfig(userConfig);
const asciimathDelimiters = config.delimiters
.filter(item => item.asciimath)
.map(({ left, right }) => {
const l = escapeRegExp(left)
const r = escapeRegExp(right)
const test = new RegExp(
`(?:${l})([^${l}${r}]+)(?:${r})`,
'g',
);
const replacer = (match, asciimath) => {
return `${left}${asciimathToTex(asciimath)}${right}`;
};
return { test, replacer };
});
return [
{
type: 'output',
filter(html = '') {
const wrapper = parser.parseFromString(html, 'text/html').body;
if (asciimathDelimiters.length) {
wrapper.querySelectorAll(':not(code):not(pre)').forEach(el => {
const textNodes = [...el.childNodes].filter(
node => {
if (node.nodeName === '#text') {
return node.nodeValue.trim()
}
if (node.nodeName === 'CODE') {
return node.innerText.trim()
}
},
)
textNodes.forEach(node => {
const newText = asciimathDelimiters.reduce(
(acc, { test, replacer }) => acc.replace(test, replacer),
node.nodeValue || node.innerText
)
if (node.nodeName === '#text') {
node.nodeValue = newText
} else {
node.innerText = newText;
}
})
})
}
// find the math in code blocks
const latex = wrapper.querySelectorAll('code.latex.language-latex');
const asciimath = wrapper.querySelectorAll(
'code.asciimath.language-asciimath',
);
renderBlockElements({ elements: latex, config });
renderBlockElements({ elements: asciimath, config, isAsciimath: true });
renderMathInElement(wrapper, config);
return wrapper.innerHTML;
},
},
];
};
// register extension with default config
showdown.extension('showdown-katex', showdownKatex());
export default showdownKatex;

@ -0,0 +1,21 @@
import test from 'ava';
import showdown from 'showdown';
import katex from '../lib/showdown-katex';
const input = '# hello, markdown!';
const output = '<h1 id="hellomarkdown">hello, markdown!</h1>';
test('string extension', t => {
const converter = new showdown.Converter({
extensions: ['showdown-katex'],
});
t.is(converter.makeHtml(input), output);
});
test('function extension', t => {
const converter = new showdown.Converter({
extensions: [katex()],
});
t.is(converter.makeHtml(input), output);
});

@ -0,0 +1,13 @@
import React from 'react'
import './index.less'
export default ({ children, style = {} }) => {
return (
<div className="dialog-container-wrapper">
<div className="dialog-body" style={style}>
{children}
</div>
</div>
)
}

@ -0,0 +1,21 @@
.dialog-container-wrapper {
display: flex;
position: fixed;
bottom: 0;
right: 0;
top: 0;
left: 0;
z-index: 300;
background: rgba(0, 0, 0, .7);
flex-flow: column nowrap;
justify-content: center;
align-items: center;
}
.dialog-body {
width: 405px;
height: auto;
background: #fff;
position: relative;
}

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

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

@ -0,0 +1,9 @@
.loading-tip {
display: flex;
flex-flow: column nowrap;
justify-content: center;
align-items: center;
height: 100%;
background: #213857;
color: #fff;
}

@ -1,5 +1,5 @@
import React, { useState } from 'react'
import './index.scss'
import './index.less'
function noop() { }
export default ({ current, defaultCurrent, total, pageSize, onChange = noop }) => {

@ -0,0 +1,65 @@
.mini-pagination {
display: flex;
flex-flow: row nowrap;
justify-content: center;
align-items: center;
a {
display: block;
padding: 0 10px 0 22px;
border-width: 1px;
border-radius: 3px;
margin-right: 4px;
font-size: 12px;
line-height: 30px;
cursor: pointer;
border-style: solid;
outline: none;
border-color: #c4c6cf;
background: #fff;
color: #333;
position: relative;
&:hover {
background-color: #f2f3f7;
border-color: #a0a2ad;
text-decoration: none;
}
&:before {
position: absolute;
content: ' ';
width: 8px;
top: 10px;
left: 10px;
height: 8px;
transform: rotate(-45deg);
border-top: 1px solid #333;
border-left: 1px solid #333;
}
&:last-child {
padding: 0 22px 0 10px;
margin: 0 0 0 4px;
&:before {
left: auto;
right: 10px;
transform: rotate(135deg);
}
}
&.disabled {
cursor: not-allowed;
background-color: #f7f8fa;
border-color: #e6e7eb;
color: #e0e0e0;
&:before {
border-top: 1px solid #e0e0e0;
border-left: 1px solid #e0e0e0;
}
}
}
}

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

@ -64,7 +64,7 @@ function getLanguageByMirrorName(mirror_name) {
export default ({
width = '100%',
height = '100%',
height = '445px',
value,
language = 'javascript',
options = {},
@ -78,20 +78,9 @@ export default ({
const [init, setInit] = useState(false)
function onLayout() {
if (window.ResizeObserver) {
const ro = new window.ResizeObserver(entries => {
for (let entry of entries) {
if (entry.target.offsetHeight > 0) {
editor.current.instance.layout()
}
}
})
ro.observe(editorEl.current.parentElement)
} else {
setTimeout(() => {
editor.current.instance.layout()
}, 100);
}
setTimeout(() => {
editor.current.instance.layout()
}, 100)
}
useEffect(() => {

@ -0,0 +1,14 @@
import React from 'react'
import { getUrl } from 'educoder'
import './index.less'
export default ({ height = 400 }) => {
return (
<div className="nodata-panel-wrapper" style={{ height }}>
<div className="nodata-panel">
<img width='128' src={getUrl("/images/educoder/nodata.png")} alt='no-data' />
<p>暂时还没有相关数据哦</p>
</div>
</div>
)
}

@ -0,0 +1,22 @@
.nodata-panel-wrapper {
display: flex;
flex-flow: column nowrap;
justify-content: center;
align-items: center;
width: 100%;
.nodata-panel {
width: 100%;
}
img {
display: block;
margin: 0 auto 20px auto;
}
p {
font-size: 20px;
text-align: center;
color: #999;
}
}

@ -0,0 +1,75 @@
import React, { Fragment } from 'react'
import { getImageUrl, setImagesUrl } from 'educoder';
import { Link } from 'react-router-dom'
import { Tooltip, Rate } from 'antd';
import './index.less'
export default ({ list = [] }) => {
return (
<Fragment>
{list.map((item, key) => {
const { id, tag_name, is_jupyter, power, identifier, pic, name, score_info, stu_num, level, challenges_count } = item
return (
<div className="square-Item" key={id} id={id}>
{
tag_name === null ? null :
<div className="tag-green">
<span className="tag-name"> {tag_name}</span>
</div>
}
{
is_jupyter === true ?
<div className="tag-org">
<p className="tag-org-name intermediatecenter"> <span className="tag-org-name-test">Jupyter</span></p>
</div>
: null
}
{power ? null
: <div className="closeSquare">
<img src={getImageUrl("images/educoder/icon/lockclose.svg")}
className="mt80 mb25" />
<p className="font-14 color-white">非试用内容需要授权</p>
</div>
}
<Link to={"/shixuns/" + identifier + "/challenges"} className="square-img" target="_blank">
<img src={setImagesUrl(`${pic}`)} />
</Link>
<div className="square-main">
<p className="task-hide">
<Link to={"/shixuns/" + identifier + "/challenges"} className="justify color-grey-name" title={name} target="_blank">
{name}
</Link>
</p>
<p className="clearfix mt8 ml-3">
<span className="rateYoStar fl" style={{ padding: '0px', height: '20px', lineHeight: '19px', cursor: 'default' }} title="">
<Rate key={key} allowHalf defaultValue={score_info === null ? 5 : score_info} disabled />
</span>
<span className="fl ml25 font-12 color-grey-9 lineh-12 mt5">{score_info === null ? "5分" : score_info + "分"}</span>
</p>
<p className="clearfix mt8 font-12 color-grey-B4">
{is_jupyter === false ? <Tooltip placement="bottom" title={"关卡"}>
<span className="mr10 fl squareIconSpan">
<i className="iconfont icon-shixunguanqia fl mr3"></i>{challenges_count}
</span>
</Tooltip> : ""}
{stu_num === 0 ? null :
<Tooltip placement="bottom" title={"学习人数"}>
<span className="mr10 fl squareIconSpan">
<i className="iconfont icon-chengyuan fl mr3"></i>{stu_num}
</span>
</Tooltip>
}
<span className="fr color-grey-B3 squareIconSpan">{level}</span>
</p>
</div>
</div>
)
})}
</Fragment>
)
}

@ -0,0 +1,36 @@
.tag-green {
position: absolute;
left: 10px;
bottom: 125px;
}
.tag-org {
position: absolute;
left: 0px;
top: 20px;
}
.tag-org-name {
width: 66px;
height: 28px;
background: #FF6802;
width: 66px;
height: 28px;
border-radius: 0px 20px 20px 0px;
}
.tag-org-name-test {
width: 45px;
height: 23px;
font-size: 14px;
color: #FFFFFF;
line-height: 19px;
margin-right: 6px;
}
.intermediatecenter {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}

@ -0,0 +1,10 @@
import React, { Fragment } from 'react';
import TPMMDEditor from '../modules/tpm/challengesnew/TPMMDEditor';
export default () => {
return (
<Fragment >
<TPMMDEditor />
</Fragment>
)
}

@ -1,21 +1,9 @@
import React, { Component } from 'react';
import React, { Component, Fragment } from 'react';
import ReactDOM from 'react-dom';
import axios from 'axios';
import Snackbar from 'material-ui/Snackbar';
import Fade from 'material-ui/transitions/Fade';
import update from 'immutability-helper'
import Dialog, {
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
} from 'material-ui/Dialog';
import Button from 'material-ui/Button';
import { Modal, Button, Alert } from 'antd'
import EvaluateSuccessEffectDisplay from './EvaluateSuccessEffectDisplay'
import _ from 'lodash'
@ -31,28 +19,15 @@ import _ from 'lodash'
*/
import TPIContext from './TPIContext'
import { EDU_ADMIN, EDU_SHIXUN_MANAGER, EDU_SHIXUN_MEMBER, EDU_CERTIFICATION_TEACHER
, EDU_GAME_MANAGER, EDU_TEACHER, EDU_NORMAL, EDU_BUSINESS, CNotificationHOC ,getRandomNumber} from 'educoder'
import { MuiThemeProvider, createMuiTheme, withStyles } from 'material-ui/styles';
import MUIDialogStyleUtil from '../modules/page/component/MUIDialogStyleUtil'
const styles = MUIDialogStyleUtil.getTwoButtonStyle()
// 主题自定义
const theme = createMuiTheme({
palette: {
primary: {
main: '#4CACFF',
contrastText: 'rgba(255, 255, 255, 0.87)'
},
secondary: { main: '#4CACFF' }, // This is just green.A700 as hex.
},
});
import {
EDU_ADMIN, EDU_SHIXUN_MANAGER, EDU_SHIXUN_MEMBER, EDU_CERTIFICATION_TEACHER
, EDU_TEACHER, EDU_NORMAL, EDU_BUSINESS, CNotificationHOC, getRandomNumber
} from 'educoder'
const testSetsExpandedArrayInitVal = [false, false, false, false, false,
false, false, false, false, false,
false, false, false, false, false,
false, false, false, false, false]
false, false, false, false, false,
false, false, false, false, false,
false, false, false, false, false]
window.__fetchAllFlag = false; // 是否调用过fetchAll TODO 如何多次使用provider
const $ = window.$
@ -105,11 +80,11 @@ class TPIContextProvider extends Component {
const dom = document.getElementById('picture_display');
window.$(dom).show();
ReactDOM.unmountComponentAtNode(dom)
ReactDOM.render(<EvaluateSuccessEffectDisplay type={"qrcode"} {...data} />, dom);
ReactDOM.render(<EvaluateSuccessEffectDisplay type={"qrcode"} {...data} />, dom);
}
onShowUpdateDialog() {
this.setState({showUpdateDialog: true})
this.setState({ showUpdateDialog: true })
}
// updateNowSuccess true 立即更新成功
// TODO updateDialogClose方法名不对 改为updateDialogCallback
@ -138,19 +113,18 @@ class TPIContextProvider extends Component {
}
componentWillUnmount() {
this._updateCostTime();
this.costTimeInterval && window.clearInterval(this.costTimeInterval)
}
componentDidMount() {
// TODO 登录状态的判断?
// request
// var shixunId = this.props.match.params.shixunId;
var stageId = this.props.match.params.stageId;
var stageId = this.props.match.params.stageId;
window.__fetchAllFlag = false;
this.fetchAll(stageId);
this.costTimeInterval = window.setInterval(()=> {
this.costTimeInterval = window.setInterval(() => {
const { game } = this.state;
if (!game || game.status === 2) { // 已完成的任务不需要计时
return;
@ -158,55 +132,35 @@ class TPIContextProvider extends Component {
if (game.cost_time || game.cost_time === 0) {
// game.cost_time += 1;
this.setState({
game: update(game, {cost_time: { $set: (game.cost_time+1) }})
game: update(game, { cost_time: { $set: (game.cost_time + 1) } })
})
}
}, 1000)
// // 页面离开时存下用户的任务耗时
window.$(window).bind('beforeunload',()=>{
this._updateCostTime();
})
// window.$(window).unload( ()=>{
// this._updateCostTime();
// });
// // 页面离开时存下用户的任务耗时
// window.$(window).unload( ()=>{
// this._updateCostTime();
// });
}
// force 评测通过后异步执行该方法强制同步costTime到服务端
_updateCostTime(async = false, force) {
const { game, loading } = this.state;
// TODO 还有一种情况通关后cost_time计时停止没法通过这个判断
if (!force && (loading || !game || game.status === 2)) {
return; // 已完成的任务不需要处理
}
if (!force && (loading || !game || game.status === 2)) {
return; // 已完成的任务不需要处理
}
let testPath = ''
if (window.location.port == 3007) {
testPath = 'http://test-newweb.educoder.net'
}
// var url = `${testPath}/api/v1/games/${ game.identifier }/cost_time`
var url = `${testPath}/api/tasks/${ game.identifier }/cost_time${getRandomNumber()}`
window.$.ajax({
type: 'get',
url: url,
async: async, //IMPORTANT, the call will be synchronous
data: {
time: game.cost_time
}
}).done((data) => {
console.log('complete');
});
var url = `${testPath}/api/tasks/${game.identifier}/cost_time${getRandomNumber()}`
window.$.ajax({
type: 'get',
url: url,
async: async, //IMPORTANT, the call will be synchronous
data: {
time: game.cost_time
}
}).done((data) => {
console.log('complete');
});
}
onGamePassed(passed) {
@ -214,7 +168,7 @@ class TPIContextProvider extends Component {
// 随便给个分以免重新评测时又出现评星组件注意目前game.star没有显示在界面上如果有则不能这么做
// game.star = 6;
this.setState({
game: update(game, {star: { $set: 6 }}),
game: update(game, { star: { $set: 6 } }),
currentGamePassed: !!passed
})
}
@ -251,40 +205,31 @@ class TPIContextProvider extends Component {
}
// praise_tread/praise_plus?obj_id=569&obj_type=Challenge&horizontal=true&game_praise=true
/*
TODO 旧的接口在未登录时的返回值
//获取登录页面地址
var signinPath = '/';
var htmlvalue = '<div class="task-popup" style="width:480px;"><div class="task-popup-title clearfix"><h3 class="fl color-grey3">提示</h3></div>'+
'<div class="task-popup-content"><p class="task-popup-text-center font-16 mt10 mb10">您还没有登录,请登录后再执行此操作,谢谢!</p></div><div class="task-popup-right-sure clearfix">'+
'<a href="javascript:void(0);" onclick="hideModal();" class="task-btn">取消</a><a href="' + signinPath + '" class="task-btn task-btn-orange ml15">登录</a></div></div>';
pop_box_new(htmlvalue, 480, 182);
*/
praisePlus() {
const { challenge, game } = this.state;
let praise = true;
const url = `/tasks/${game.identifier}/plus_or_cancel_praise.json`
// const url = `/praise_tread/praise_plus?obj_id=${challenge.id}&obj_type=Challenge&horizontal=${praise}&game_praise=true`
axios.post(url)
.then((response) => {
if (response.data) {
const { praise_count, praise } = response.data;
// challenge.praise_count = praise_tread_count;
// challenge.user_praise = praise;
this.setState({ challenge: update(challenge,
{
praise_count: { $set: praise_count },
user_praise: { $set: praise },
})
})
}
})
.catch(function (error) {
console.log(error);
});
.then((response) => {
if (response.data) {
const { praise_count, praise } = response.data;
// challenge.praise_count = praise_tread_count;
// challenge.user_praise = praise;
this.setState({
challenge: update(challenge,
{
praise_count: { $set: praise_count },
user_praise: { $set: praise },
})
})
}
})
.catch(function (error) {
console.log(error);
});
}
onPathChange(index, callback) {
@ -292,7 +237,7 @@ pop_box_new(htmlvalue, 480, 182);
// challenge = Object.assign({}, challenge)
// challenge.pathIndex = index;
this.setState({
challenge: update(challenge, {pathIndex: { $set: index }}),
challenge: update(challenge, { pathIndex: { $set: index } }),
}, () => {
callback && callback()
})
@ -310,25 +255,26 @@ pop_box_new(htmlvalue, 480, 182);
challenge.path = path;
const newChallenge = this.handleChallengePath(challenge);
this.setState({ challenge: newChallenge,
myshixun: update(myshixun, {system_tip: { $set: false }}),
this.setState({
challenge: newChallenge,
myshixun: update(myshixun, { system_tip: { $set: false } }),
})
}
handleChallengePath(challenge) {
if (challenge.path && typeof challenge.path === "string") { // 多path的处理
let path = challenge.path.split('');
_.remove(path, (item)=> !item)
if (path.length > 1) {
challenge.path = path;
challenge.multiPath = true;
} else {
challenge.path = challenge.path.replace('', '').trim() // 多path 改为单path 出现了 aaa.java的情况
challenge.multiPath = false;
}
}
challenge.pathIndex = 0;
return challenge;
let path = challenge.path.split('');
_.remove(path, (item) => !item)
if (path.length > 1) {
challenge.path = path;
challenge.multiPath = true;
} else {
challenge.path = challenge.path.replace('', '').trim() // 多path 改为单path 出现了 aaa.java的情况
challenge.multiPath = false;
}
}
challenge.pathIndex = 0;
return challenge;
}
newResData2OldResData(newResData) {
@ -350,89 +296,82 @@ pop_box_new(htmlvalue, 480, 182);
newResData.output_sets.test_sets_count = newResData.test_sets_count
// newResData.output_sets.had_passed_testsests_error_count = newResData.sets_error_count
newResData.output_sets.had_passed_testsests_error_count = newResData.test_sets_count
- newResData.sets_error_count
// allowed_hidden_testset
// sets_error_count
// test_sets_count
// test_sets
// had_passed_testsests_error_count
// test_sets
// test_sets
- newResData.sets_error_count
return newResData
}
// 将若干数据重新组织一下
_handleResponseData(resData_arg) {
const resData = this.newResData2OldResData(Object.assign({}, resData_arg))
let challenge = resData.challenge;
challenge.isHtml = false;
challenge.isWeb = false;
challenge.isAndroid = false;
challenge.showLanguagePictrue = false;
challenge.hasAnswer = resData.has_answer;
let output_sets = resData.output_sets;
let challenge = resData.challenge;
challenge.isHtml = false;
challenge.isWeb = false;
challenge.isAndroid = false;
challenge.showLanguagePictrue = false;
challenge.hasAnswer = resData.has_answer;
let output_sets = resData.output_sets;
if (resData.st === 0) { // 代码题
challenge = this.handleChallengePath(challenge)
const mirror_name = (resData.mirror_name && resData.mirror_name.join)
? resData.mirror_name.join(';') : (resData.mirror_name || '');
if (mirror_name.indexOf('Html') !== -1) {
challenge.isHtml = true;
challenge.showLanguagePictrue = true;
} else if (mirror_name.indexOf('Web') !== -1 || mirror_name.indexOf('JFinal') !== -1) {
challenge.isWeb = true;
} else if (mirror_name.indexOf('Android') !== -1) {
challenge.isAndroid = true;
}
if (output_sets && output_sets.test_sets && typeof output_sets.test_sets == 'string') {
const test_sets_array = JSON.parse("[" + output_sets.test_sets + "]");
output_sets.test_sets_array = test_sets_array;
} else {
output_sets.test_sets_array = output_sets.test_sets
}
} else { // 选择题
// 选择题题干markdown初始化
const $ = window.$
window.setTimeout(()=>{
challenge = this.handleChallengePath(challenge)
const mirror_name = (resData.mirror_name && resData.mirror_name.join)
? resData.mirror_name.join(';') : (resData.mirror_name || '');
if (mirror_name.indexOf('Html') !== -1) {
challenge.isHtml = true;
challenge.showLanguagePictrue = true;
} else if (mirror_name.indexOf('Web') !== -1 || mirror_name.indexOf('JFinal') !== -1) {
challenge.isWeb = true;
} else if (mirror_name.indexOf('Android') !== -1) {
challenge.isAndroid = true;
}
if (output_sets && output_sets.test_sets && typeof output_sets.test_sets == 'string') {
const test_sets_array = JSON.parse("[" + output_sets.test_sets + "]");
output_sets.test_sets_array = test_sets_array;
} else {
output_sets.test_sets_array = output_sets.test_sets
}
} else { // 选择题
// 选择题题干markdown初始化
const $ = window.$
window.setTimeout(() => {
var lens = $("#choiceRepositoryView textarea").length;
for(var i = 1; i <= lens; i++){
window.editormd.markdownToHTML("choose_subject_" + i, {
htmlDecode: "style,script,iframe", // you can filter tags decode
taskList: true,
tex: true, // 数学公式
// flowChart: true, // 默认不解析
// sequenceDiagram: true // 默认不解析
});
}
}, 400)
}
challenge.user_praise = resData.user_praise;
challenge.praise_count = resData.praise_count;
challenge.showWebDisplayButton = false;
resData.challenge = challenge;
// 将一些属性写到game上
let game = resData.game;
game.prev_game = resData.prev_game;
game.next_game = resData.next_game;
for (var i = 1; i <= lens; i++) {
window.editormd.markdownToHTML("choose_subject_" + i, {
htmlDecode: "style,script,iframe", // you can filter tags decode
taskList: true,
tex: true, // 数学公式
// flowChart: true, // 默认不解析
// sequenceDiagram: true // 默认不解析
});
}
}, 400)
}
challenge.user_praise = resData.user_praise;
challenge.praise_count = resData.praise_count;
challenge.showWebDisplayButton = false;
resData.challenge = challenge;
// 将一些属性写到game上
let game = resData.game;
game.prev_game = resData.prev_game;
game.next_game = resData.next_game;
if (game.status == 2) {
// 已通关
game.isPassThrough = true
}
resData.game = game;
resData.game = game;
const { tpm_cases_modified, tpm_modified, tpm_script_modified, myshixun } = resData;
if (myshixun.system_tip) {
const { tpm_cases_modified, tpm_modified, tpm_script_modified, myshixun } = resData;
if (myshixun.system_tip) {
// system_tip为true的时候 不弹框提示用户更新
resData.showUpdateDialog = false
} else {
let needUpdateScript = (tpm_modified || tpm_script_modified) && challenge.st === 0;
resData.showUpdateDialog = needUpdateScript || tpm_cases_modified
}
resData.showUpdateDialog = false
} else {
let needUpdateScript = (tpm_modified || tpm_script_modified) && challenge.st === 0;
resData.showUpdateDialog = needUpdateScript || tpm_cases_modified
}
/**
email: "721773699@qq.com"
@ -443,29 +382,29 @@ pop_box_new(htmlvalue, 480, 182);
name: "Coder"
user_url: "/users/innov"
*/
let user = resData.user;
user.username = resData.user.name;
user.user_url = `/users/${resData.user.login}`;
// user.image_url = resData.image_url;
user.is_teacher = resData.is_teacher;
resData.user = user;
this._handleUserAuthor(resData)
// TODO 测试
// resData.power = 0;
let user = resData.user;
user.username = resData.user.name;
user.user_url = `/users/${resData.user.login}`;
// user.image_url = resData.image_url;
user.is_teacher = resData.is_teacher;
resData.user = user;
this._handleUserAuthor(resData)
// TODO 测试
// resData.power = 0;
resData.shixun.vnc = !!resData.vnc_url
resData.shixun.vnc_evaluate = resData.vnc_evaluate
this.setState({
...resData,
currentGamePassed: false,
loading: false,
testSetsExpandedArray: testSetsExpandedArrayInitVal.slice(0),
})
this.setState({
...resData,
currentGamePassed: false,
loading: false,
testSetsExpandedArray: testSetsExpandedArrayInitVal.slice(0),
})
window.document.title = resData.shixun.name
window.document.title = resData.shixun.name
window.__myshixun = resData.myshixun; // tpi_html_show需要用到
window.__myshixun = resData.myshixun; // tpi_html_show需要用到
}
_handleUserAuthor(resData) {
// tpi tpm权限控制
@ -522,7 +461,7 @@ pop_box_new(htmlvalue, 480, 182);
fetchAll(stageId, noTimeout) {
if (window.__fetchAllFlag == true ) {
if (window.__fetchAllFlag == true) {
console.log('TPIContextProvider call fetchAll repeatly!')
return;
}
@ -541,9 +480,9 @@ pop_box_new(htmlvalue, 480, 182);
this.setState({
loading: true,
currentGamePassed: false, // 切换game时重置passed字段
})
loading: true,
currentGamePassed: false, // 切换game时重置passed字段
})
// test
// var data = {"st":0,"discusses_count":0,"game_count":3,"record_onsume_time":0.36,"prev_game":null,"next_game":"7p9xwo2hklqv","praise_count":0,"user_praise":false,"time_limit":20,"tomcat_url":"http://47.96.157.89","is_teacher":false,"myshixun_manager":true,"game":{"id":2192828,"myshixun_id":580911,"user_id":57844,"created_at":"2019-09-03T15:50:49.000+08:00","updated_at":"2019-09-03T15:51:05.000+08:00","status":2,"final_score":0,"challenge_id":10010,"open_time":"2019-09-03T15:50:49.000+08:00","identifier":"hknvz4oaw825","answer_open":0,"end_time":"2019-09-03T15:51:04.000+08:00","retry_status":0,"resubmit_identifier":null,"test_sets_view":false,"picture_path":null,"accuracy":1.0,"modify_time":"2019-09-03T15:23:33.000+08:00","star":0,"cost_time":14,"evaluate_count":1,"answer_deduction":0},"challenge":{"id":10010,"shixun_id":3516,"subject":"1.1 列表操作","position":1,"task_pass":"[TOC]\n\n---\n\n####任务描述\n\n\n数据集a包含1-10共10个整数请以a为输入数据编写python程序实现如下功能\n①\t用2种方法输出a中所有奇数\n②\t输出大于3小于7的偶数\n③\t用2种方法输出[1,2,3,…10,11,…20]\n④\t输出a的最大值、最小值。\n⑤\t用2种方法输出[10,9,…2,1]\n⑥\t输出[1,2,3,1,2,3,1,2,3,1,2,3]\n\n\n####相关知识\n\n\n请自行学习相关知识\n\n\n---\n开始你的任务吧祝你成功","score":100,"path":"1-1-stu.py","st":0,"web_route":null,"modify_time":"2019-09-03T15:23:33.000+08:00","exec_time":20,"praises_count":0},"shixun":{"id":3516,"name":"作业1——Python程序设计","user_id":77620,"gpid":null,"visits":23,"created_at":"2019-09-03T14:18:17.000+08:00","updated_at":"2019-09-03T15:58:16.000+08:00","status":0,"language":null,"authentication":false,"identifier":"6lzjig58","trainee":1,"major_id":null,"webssh":2,"homepage_show":false,"hidden":false,"fork_from":null,"can_copy":true,"modify_time":"2019-09-03T14:18:17.000+08:00","reset_time":"2019-09-03T14:18:17.000+08:00","publish_time":null,"closer_id":null,"end_time":null,"git_url":null,"vnc":null,"myshixuns_count":3,"challenges_count":3,"use_scope":0,"mirror_script_id":20,"image_text":null,"code_hidden":false,"task_pass":true,"exec_time":20,"test_set_permission":true,"sigle_training":false,"hide_code":false,"multi_webssh":false,"excute_time":null,"repo_name":"p09218567/6lzjig58","averge_star":5.0,"opening_time":null,"users_count":1,"forbid_copy":false,"pod_life":0},"myshixun":{"id":580911,"shixun_id":3516,"is_public":true,"user_id":57844,"gpid":null,"created_at":"2019-09-03T15:50:49.000+08:00","updated_at":"2019-09-03T15:59:04.000+08:00","status":0,"identifier":"k36hm4rwav","commit_id":"f25e1713882156480fc45ce0af57eff395a5037f","modify_time":"2019-09-03T14:18:17.000+08:00","reset_time":"2019-09-03T14:18:17.000+08:00","system_tip":false,"git_url":null,"onclick_time":"2019-09-03T15:50:49.000+08:00","repo_name":"p53276410/k36hm4rwav20190903155049"},"user":{"user_id":57844,"login":"p53276410","name":"文振乾","grade":24624,"identity":1,"image_url":"avatars/User/57844","school":"EduCoder团队"},"tpm_modified":true,"tpm_cases_modified":false,"mirror_name":["Python3.6"],"has_answer":false,"test_sets":[{"is_public":true,"result":true,"input":"","output":"result of a:\n[1, 3, 5, 7, 9]\n[1, 3, 5, 7, 9]\nresult of b:\n[2, 4, 6, 8, 10]\nresult of c:\n[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]\n[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]\nresult of d:\nThe minimum is:1\nThe maxium is:10\nresult of e:\n[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]\n[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\nresult of f:\n[10, 9, 8, 10, 9, 8, 10, 9, 8, 10, 9, 8]\n","actual_output":"result of a:\r\n[1, 3, 5, 7, 9]\r\n[1, 3, 5, 7, 9]\r\nresult of b:\r\n[2, 4, 6, 8, 10]\r\nresult of c:\r\n[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]\r\n[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]\r\nresult of d:\r\nThe minimum is:1\r\nThe maxium is:10\r\nresult of e:\r\n[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]\r\n[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\r\nresult of f:\r\n[10, 9, 8, 10, 9, 8, 10, 9, 8, 10, 9, 8]\r\n","compile_success":1,"ts_time":0.05,"ts_mem":8.77}],"allowed_unlock":true,"last_compile_output":"compile successfully","test_sets_count":1,"sets_error_count":0}
@ -557,19 +496,19 @@ pop_box_new(htmlvalue, 480, 182);
// return
axios.get(url, {
// https://stackoverflow.com/questions/48861290/the-value-of-the-access-control-allow-origin-header-in-the-response-must-not-b
// withCredentials: true,
})
.then((response) => {
// {"status":1,"message":"Unauthorized. \u7528\u6237\u8ba4\u8bc1\u5931\u8d25."}
// https://stackoverflow.com/questions/48861290/the-value-of-the-access-control-allow-origin-header-in-the-response-must-not-b
// withCredentials: true,
})
.then((response) => {
// {"status":1,"message":"Unauthorized. \u7528\u6237\u8ba4\u8bc1\u5931\u8d25."}
window.__fetchAllFlag = false;
if (response.data.status == 403) {
if (response.data.status == 403) {
window.location.href = "/403";
return;
}
if (response.data.status == 404) {
return;
}
if (response.data.status == 404) {
// 如果第一次发生404则隔1s后再调用一次本接口因为ucloud主从同步可能有延迟
if (!noTimeout) {
setTimeout(() => {
@ -577,16 +516,16 @@ pop_box_new(htmlvalue, 480, 182);
}, 1000)
return;
}
window.location.href = '/myshixuns/not_found'
return;
}
window.location.href = '/myshixuns/not_found'
return;
}
this._handleResponseData(response.data)
this._handleResponseData(response.data)
})
.catch(function (error) {
console.log(error);
});
})
.catch(function (error) {
console.log(error);
});
}
@ -595,7 +534,7 @@ pop_box_new(htmlvalue, 480, 182);
if (resData.final_score) {
var game = this.state.game;
this.setState({
game: update(game, {final_score: { $set: resData.final_score }}),
game: update(game, { final_score: { $set: resData.final_score } }),
grade: resData.grade
})
} else {
@ -609,7 +548,7 @@ pop_box_new(htmlvalue, 480, 182);
this.setState({
game: (this.state.game.status == 2 ? update(this.state.game, {
isPassThrough: { $set: true },
}) : this.state.game) ,
}) : this.state.game),
currentGamePassed: false
})
}
@ -645,10 +584,11 @@ pop_box_new(htmlvalue, 480, 182);
window.clearTimeout(this.showWebDisplayButtonTimeout)
}
this.showWebDisplayButtonTimeout = window.setTimeout(() => {
this.setState({ challenge: update(challenge,
{
showWebDisplayButton: { $set: false },
})
this.setState({
challenge: update(challenge,
{
showWebDisplayButton: { $set: false },
})
})
this.showWebDisplayButtonTimeout = null
}, 61 * 1000)
@ -677,52 +617,28 @@ pop_box_new(htmlvalue, 480, 182);
language_display(data) {
const { game, tomcat_url } = this.state;
const challenge = Object.assign({}, this.state.challenge)
if(challenge.isWeb && data.port != -1) {
// var $result = $("#php_display");
challenge.showWebDisplayButton = true; // ActionView处是否出现查看效果按钮
if (challenge.isWeb && data.port != -1) {
// var $result = $("#php_display");
challenge.showWebDisplayButton = true; // ActionView处是否出现查看效果按钮
this.initDisplayInterval()
const path = challenge.web_route || challenge.path
const webDisplayUrl = `${tomcat_url}:${data.port}/${path}`
challenge.webDisplayUrl = webDisplayUrl
challenge.showLanguagePictrue = true; // 评测通过弹出层是否出现查看效果按钮
}
// else if(challenge.isAndroid && data.picture != 0){
// // https://www.educoder.net/shixuns/qrcode?game_id=218589&_=1525571882782
// $.ajax({
// url: `/shixuns/qrcode?game_id=${game.id}`,
// dataType: 'script'
// });
// challenge.showLanguagePictrue = true;
// }
else if(data.picture != 0){
// 对应服务端erb文件为 _picture_display.html.erb
// $.ajax({
// url: "/users/picture_show?game_id="+data.picture,
// cache: false,
// dataType: 'script'
// });
/**
{
"type": "image",
"orignal_picture": [],
"user_picture": [],
"answer_picture": []
}
*/
const path = challenge.web_route || challenge.path
const webDisplayUrl = `${tomcat_url}:${data.port}/${path}`
challenge.webDisplayUrl = webDisplayUrl
challenge.showLanguagePictrue = true; // 评测通过弹出层是否出现查看效果按钮
}
else if (data.picture != 0) {
const url = `/tasks/${game.identifier}/picture_display.json`
axios.get(url)
.then((response) => {
// response.data.type qrcode_str
.then((response) => {
this.showEffectDisplay(response.data)
})
challenge.showLanguagePictrue = true;
}
this.setState({
challenge
})
challenge.showLanguagePictrue = true;
}
this.setState({
challenge
})
}
onRunCodeTestFinish(response) {
console.log('onRunCodeTestFinish', response)
@ -730,7 +646,7 @@ pop_box_new(htmlvalue, 480, 182);
, had_test_count, had_passed_testsests_error_count, had_passed_testsests_hidden_count
, had_passed_testsests_public_count, final_score, gold, experience, latest_output, status
, had_done, score, tag_count, power, record, next_game, grade, picture,
sets_error_count, last_compile_output, record_consume_time} = response;
sets_error_count, last_compile_output, record_consume_time } = response;
const { game } = this.state;
@ -745,19 +661,19 @@ pop_box_new(htmlvalue, 480, 182);
const output_sets = {
"test_sets": test_sets,
"test_sets_array": test_sets,
"had_test_count": had_test_count || test_sets_count,
"test_sets_count": test_sets_count,
// "had_passed_testsests_error_count": had_passed_testsests_error_count,
"had_passed_testsests_error_count": test_sets_count - sets_error_count,
"test_sets_hidden_count": test_sets_hidden_count,
"test_sets_public_count": test_sets_public_count,
"had_passed_testsests_hidden_count": had_passed_testsests_hidden_count,
"had_passed_testsests_public_count": had_passed_testsests_public_count
"had_test_count": had_test_count || test_sets_count,
"test_sets_count": test_sets_count,
// "had_passed_testsests_error_count": had_passed_testsests_error_count,
"had_passed_testsests_error_count": test_sets_count - sets_error_count,
"test_sets_hidden_count": test_sets_hidden_count,
"test_sets_public_count": test_sets_public_count,
"had_passed_testsests_hidden_count": had_passed_testsests_hidden_count,
"had_passed_testsests_public_count": had_passed_testsests_public_count
};
// if (output_sets && output_sets.test_sets) {
// const test_sets_array = JSON.parse("[" + output_sets.test_sets + "]");
// output_sets.test_sets_array = test_sets_array;
// }
// const test_sets_array = JSON.parse("[" + output_sets.test_sets + "]");
// output_sets.test_sets_array = test_sets_array;
// }
// 检查是否编译通过
let compileSuccess = false;
@ -813,35 +729,35 @@ pop_box_new(htmlvalue, 480, 182);
const { game, challenge } = this.state;
const url = `/tasks/${game.identifier}/check_test_sets.json`
axios.get(url, {
// withCredentials: true,
})
.then((response) => {
// withCredentials: true,
})
.then((response) => {
// TODO status -2 重复操作,直接解锁
if (response.data.test_sets == -1) {
console.error('testSetUnlock失败')
this.showSnackbar(response.data.message)
return;
} else {
// 被扣除的金币,是负数
const deltaScore = -challenge.score * 5;
if (response.data.test_sets == -1) {
console.error('testSetUnlock失败')
this.showSnackbar(response.data.message)
return;
} else {
// 被扣除的金币,是负数
const deltaScore = -challenge.score * 5;
// output_sets
let { output_sets } = this.state;
output_sets = Object.assign({}, output_sets);
// const test_sets_array = JSON.parse("[" + response.data.test_sets + "]");
output_sets.test_sets_array = response.data.test_sets;
this.setState({
output_sets.test_sets_array = response.data.test_sets;
this.setState({
output_sets: output_sets,
grade: this.state.grade + deltaScore,
game : update(game, {test_sets_view: { $set: true }}),
testSetsExpandedArray: testSetsExpandedArrayInitVal.slice(0)
})
this.handleGdialogClose();
}
grade: this.state.grade + deltaScore,
game: update(game, { test_sets_view: { $set: true } }),
testSetsExpandedArray: testSetsExpandedArrayInitVal.slice(0)
})
this.handleGdialogClose();
}
})
.catch(function (error) {
console.log(error);
});
})
.catch(function (error) {
console.log(error);
});
}
handleSnackbarClose() {
@ -884,9 +800,6 @@ pop_box_new(htmlvalue, 480, 182);
onGdialogOkBtnClick() {
this.dialogOkCallback && this.dialogOkCallback();
// this.setState({
// gDialogOpen: true
// })
}
handleGdialogClose = () => {
this.setState({
@ -894,96 +807,87 @@ pop_box_new(htmlvalue, 480, 182);
})
}
render() {
const { classes } = this.props;
return (
<TPIContext.Provider
value={{
...this.props,
...this.state,
resetTestSetsExpandedArray: this.resetTestSetsExpandedArray,
onRunCodeTestFinish: this.onRunCodeTestFinish,
onRunChooseTestFinish: this.onRunChooseTestFinish,
testSetUnlock: this.testSetUnlock,
onTestSetHeaderClick: this.onTestSetHeaderClick,
readGameAnswer: this.readGameAnswer,
onShowPrevStage: this.onShowPrevStage,
onShowNextStage: this.onShowNextStage,
praisePlus: this.praisePlus,
onGamePassed: this.onGamePassed,
closeTaskResultLayer: () => this.closeTaskResultLayer(),
onPathChange: this.onPathChange,
updateChallengePath: this.updateChallengePath,
showSnackbar: this.showSnackbar,
showDialog: this.showDialog,
handleGdialogClose: () => this.handleGdialogClose(),
onShowUpdateDialog: this.onShowUpdateDialog,
updateDialogClose: this.updateDialogClose,
match: this.props.match
}}
>
<Dialog
id="tpi-dialog"
open={this.state.gDialogOpen}
disableEscapeKeyDown={true}
onClose={() => this.handleGdialogClose()}
>
<DialogTitle id="alert-dialog-title">{"提示"}</DialogTitle>
<DialogContent id="dialog-content">
<DialogContentText id="alert-dialog-description" style={{textAlign: 'center'}}>
{this.state.gDialogContentText}
</DialogContentText>
</DialogContent>
{/* mb20 加了有样式问题 */}
<DialogActions className={""} id="dialog-actions">
{ this.isSingleButton ? <div className="task-popup-submit clearfix"
style={{ textAlign: 'center', 'margin-bottom': '14px'}}>
<a className="task-btn task-btn-orange"
onClick={this.handleGdialogClose}
>知道啦</a>
</div> :
<React.Fragment>
<Button onClick={() => this.handleGdialogClose()} color="primary"
className={`${classes.button} ${classes.buttonGray} ${classes.borderRadiusNone}`}>
关闭
</Button>
<Button variant="raised" className={`${classes.button} ${classes.borderRadiusNone}`}
onClick={() => this.onGdialogOkBtnClick() } color="primary" autoFocus>
{ this.okButtonText ? this.okButtonText : '确定' }
<TPIContext.Provider
value={{
...this.props,
...this.state,
resetTestSetsExpandedArray: this.resetTestSetsExpandedArray,
onRunCodeTestFinish: this.onRunCodeTestFinish,
onRunChooseTestFinish: this.onRunChooseTestFinish,
testSetUnlock: this.testSetUnlock,
onTestSetHeaderClick: this.onTestSetHeaderClick,
readGameAnswer: this.readGameAnswer,
onShowPrevStage: this.onShowPrevStage,
onShowNextStage: this.onShowNextStage,
praisePlus: this.praisePlus,
onGamePassed: this.onGamePassed,
closeTaskResultLayer: () => this.closeTaskResultLayer(),
onPathChange: this.onPathChange,
updateChallengePath: this.updateChallengePath,
showSnackbar: this.showSnackbar,
showDialog: this.showDialog,
handleGdialogClose: () => this.handleGdialogClose(),
onShowUpdateDialog: this.onShowUpdateDialog,
updateDialogClose: this.updateDialogClose,
match: this.props.match
}}
>
<Modal
id="tpi-dialog"
title='提示'
visible={this.state.gDialogOpen}
onCancel={() => this.handleGdialogClose()}
footer={
<Fragment>
{this.isSingleButton ? <div className="task-popup-submit clearfix"
style={{ textAlign: 'center', 'margin-bottom': '14px' }}>
<a className="task-btn task-btn-orange"
onClick={this.handleGdialogClose}
>知道啦</a>
</div> :
<React.Fragment>
<Button onClick={() => this.handleGdialogClose()} color="primary">
关闭
</Button>
</React.Fragment> }
{this.moreButtonsRender && this.moreButtonsRender()}
</DialogActions>
</Dialog>
<Snackbar
<Button variant="raised"
onClick={() => this.onGdialogOkBtnClick()} color="primary" autoFocus>
{this.okButtonText ? this.okButtonText : '确定'}
</Button>
</React.Fragment>}
{this.moreButtonsRender && this.moreButtonsRender()}
</Fragment>
}
>
<div id="alert-dialog-description" style={{ textAlign: 'center' }}>
{this.state.gDialogContentText}
</div>
</Modal>
{this.state.snackbarOpen ?
<Alert
className={"rootSnackbar"}
open={this.state.snackbarOpen}
autoHideDuration={3000}
anchorOrigin={{ vertical: this.state.snackbarVertical || 'top'
, horizontal: this.state.snackbarHorizontal || 'center' }}
onClose={() => this.handleSnackbarClose()}
transition={Fade}
SnackbarContentProps={{
'aria-describedby': 'message-id',
}}
resumeHideDuration={2000}
message={<span id="message-id">{this.state.snackbarText}</span>}
/>
{this.props.children}
</TPIContext.Provider>
onClose={() => this.handleSnackbarClose()}
message={<span id="message-id">{this.state.snackbarText}</span>}
/> : null
}
{this.props.children}
</TPIContext.Provider>
)
}
}
export default CNotificationHOC() (withStyles(styles) (TPIContextProvider));
export default CNotificationHOC()(TPIContextProvider);

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

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

@ -1,4 +0,0 @@
/* material ui 给body加了个6px padding */
body {
padding-right: 0px !important;
}

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

After

Width:  |  Height:  |  Size: 2.6 KiB

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

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

@ -1,37 +1,32 @@
import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
import Loading from '../../Loading';
import TPMIndexHOC from '../tpm/TPMIndexHOC';
import Loadable from 'react-loadable';
import { TPMIndexHOC } from '../tpm/TPMIndexHOC';
import { SnackbarHOC,getImageUrl } from 'educoder';
import { SnackbarHOC, getImageUrl } from 'educoder';
class Shixunauthority extends Component {
render() {
return (
<div className="newMain clearfix">
<div className=" edu-txt-center mt60 mb60">
{/*mt100 mb100*/}
<img src={getImageUrl("images/warn/pic_403.jpg")} />
<p className="font-18 mt40">
您可以稍后尝试&nbsp;<a href="/"
className="color-blue">返回首页</a>
或者&nbsp;
<div className=" edu-txt-center mt60 mb60">
{/*mt100 mb100*/}
<img src={getImageUrl("images/warn/pic_403.jpg")} />
<p className="font-18 mt40">
您可以稍后尝试&nbsp;<a href="/"
className="color-blue">返回首页</a>
或者&nbsp;
<a target="_blank"
href="//shang.qq.com/wpa/qunwpa?idkey=2f2043d88c1bd61d182b98bf1e061c6185e23055bec832c07d8148fe11c5a6cd"
className="color-blue">QQ反馈&gt;&gt;</a>
</p>
</div>
{/*<div style="clear:both;"></div>*/}
{/*<div id="ajax-indicator" style="display:none;"><span>载入中...</span></div>*/}
{/*<div id="ajax-modal" style="display:none;"></div>*/}
href="//shang.qq.com/wpa/qunwpa?idkey=2f2043d88c1bd61d182b98bf1e061c6185e23055bec832c07d8148fe11c5a6cd"
className="color-blue">QQ反馈&gt;&gt;</a>
</p>
</div>
{/*<div style="clear:both;"></div>*/}
{/*<div id="ajax-indicator" style="display:none;"><span>载入中...</span></div>*/}
{/*<div id="ajax-modal" style="display:none;"></div>*/}
</div>
);
}
}
export default SnackbarHOC() (TPMIndexHOC ( Shixunauthority ));
export default SnackbarHOC()(TPMIndexHOC(Shixunauthority));

@ -4,34 +4,34 @@ import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
import Loading from '../../Loading';
import Loadable from 'react-loadable';
import { Loadable } from 'educoder';
import { TPMIndexHOC } from '../tpm/TPMIndexHOC';
import TPMIndexHOC from '../tpm/TPMIndexHOC';
import { SnackbarHOC,getImageUrl } from 'educoder';
import { SnackbarHOC, getImageUrl } from 'educoder';
class http500 extends Component {
render() {
return (
<div className="newMain clearfix">
<div className=" edu-txt-center mt60 mb60">
{/*mt100 mb100*/}
<img src={getImageUrl("images/warn/pic_404.jpg")} />
<p className="font-18 mt40">
您可以稍后尝试&nbsp;<a href="/"
className="color-blue">返回首页</a>
或者&nbsp;
<div className=" edu-txt-center mt60 mb60">
{/*mt100 mb100*/}
<img src={getImageUrl("images/warn/pic_404.jpg")} />
<p className="font-18 mt40">
您可以稍后尝试&nbsp;<a href="/"
className="color-blue">返回首页</a>
或者&nbsp;
<a target="_blank"
href="//shang.qq.com/wpa/qunwpa?idkey=2f2043d88c1bd61d182b98bf1e061c6185e23055bec832c07d8148fe11c5a6cd"
className="color-blue">QQ反馈&gt;&gt;</a>
</p>
</div>
{/*<div style="clear:both;"></div>*/}
{/*<div id="ajax-indicator" style="display:none;"><span>载入中...</span></div>*/}
{/*<div id="ajax-modal" style="display:none;"></div>*/}
href="//shang.qq.com/wpa/qunwpa?idkey=2f2043d88c1bd61d182b98bf1e061c6185e23055bec832c07d8148fe11c5a6cd"
className="color-blue">QQ反馈&gt;&gt;</a>
</p>
</div>
{/*<div style="clear:both;"></div>*/}
{/*<div id="ajax-indicator" style="display:none;"><span>载入中...</span></div>*/}
{/*<div id="ajax-modal" style="display:none;"></div>*/}
</div>
);
}
}
export default SnackbarHOC() (TPMIndexHOC ( http500 ));
export default SnackbarHOC()(TPMIndexHOC(http500));

@ -4,34 +4,34 @@ import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
import Loading from '../../Loading';
import Loadable from 'react-loadable';
import { Loadable } from 'educoder';
import { TPMIndexHOC } from '../tpm/TPMIndexHOC';
import TPMIndexHOC from '../tpm/TPMIndexHOC';
import { SnackbarHOC,getImageUrl } from 'educoder';
import { SnackbarHOC, getImageUrl } from 'educoder';
class Shixunnopage extends Component {
render() {
return (
<div className="newMain clearfix">
<div className=" edu-txt-center mt60 mb60">
{/*mt100 mb100*/}
<img src={getImageUrl("images/warn/pic_500.jpg")} />
<p className="font-18 mt40">
您可以稍后尝试&nbsp;<a href="/"
className="color-blue">返回首页</a>
或者&nbsp;
<div className=" edu-txt-center mt60 mb60">
{/*mt100 mb100*/}
<img src={getImageUrl("images/warn/pic_500.jpg")} />
<p className="font-18 mt40">
您可以稍后尝试&nbsp;<a href="/"
className="color-blue">返回首页</a>
或者&nbsp;
<a target="_blank"
href="//shang.qq.com/wpa/qunwpa?idkey=2f2043d88c1bd61d182b98bf1e061c6185e23055bec832c07d8148fe11c5a6cd"
className="color-blue">QQ反馈&gt;&gt;</a>
</p>
</div>
{/*<div style="clear:both;"></div>*/}
{/*<div id="ajax-indicator" style="display:none;"><span>载入中...</span></div>*/}
{/*<div id="ajax-modal" style="display:none;"></div>*/}
href="//shang.qq.com/wpa/qunwpa?idkey=2f2043d88c1bd61d182b98bf1e061c6185e23055bec832c07d8148fe11c5a6cd"
className="color-blue">QQ反馈&gt;&gt;</a>
</p>
</div>
{/*<div style="clear:both;"></div>*/}
{/*<div id="ajax-indicator" style="display:none;"><span>载入中...</span></div>*/}
{/*<div id="ajax-modal" style="display:none;"></div>*/}
</div>
);
}
}
export default SnackbarHOC() (TPMIndexHOC ( Shixunnopage ));
export default SnackbarHOC()(TPMIndexHOC(Shixunnopage));

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

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

Loading…
Cancel
Save