dev_aliyun_beta
杨树林 5 years ago
commit d66fe97179

@ -13,6 +13,7 @@
//= require bootstrap-datepicker
//= require bootstrap.viewer
//= require echarts
//= require lib/codemirror
//= require mode/shell/shell

@ -0,0 +1,66 @@
$(document).on('turbolinks:load', function() {
if ($('body.admins-dashboards-index-page').length > 0) {
// 月新增用户
var monthChart = echarts.init(document.getElementById('month-active-user'));
monthChart.setOption({
tooltip: {
show: "true",
trigger: 'item',
formatter: '{c0}',
backgroundColor: 'rgba(0,0,0,0.7)', // 背景
padding: [8, 10], //内边距
extraCssText: 'box-shadow: 0 0 3px rgba(255, 255, 255, 0.4);', //添加阴影
axisPointer: { // 坐标轴指示器,坐标轴触发有效
type: 'shadow' // 默认为直线,可选为:'line' | 'shadow'
}
},
series : [
{
name: '访问来源',
type: 'pie',
radius: '55%',
data: []
}
]
});
monthChart.showLoading();
$.get('/admins/dashboards/month_active_user.json').done(function(data){
monthChart.setOption({
series: [
{ data: data.data }
]
});
monthChart.hideLoading();
});
// 近七天评测次数
var evaluateChart = echarts.init(document.getElementById('evaluate-pie'));
evaluateChart.setOption({
tooltip: {
show: "true",
trigger: 'item',
formatter: '{c0}',
backgroundColor: 'rgba(0,0,0,0.7)', // 背景
padding: [8, 10], //内边距
extraCssText: 'box-shadow: 0 0 3px rgba(255, 255, 255, 0.4);', //添加阴影
axisPointer: { // 坐标轴指示器,坐标轴触发有效
type: 'shadow' // 默认为直线,可选为:'line' | 'shadow'
}
},
xAxis: { type: 'category', boundaryGap: false, data: [] },
yAxis: { type: 'value' },
series: [{ data: [], type: 'line', areaStyle: {} }]
});
evaluateChart.showLoading();
$.get('/admins/dashboards/evaluate.json').done(function(data){
evaluateChart.setOption({
xAxis: { data: data.names },
series: [{ data: data.data }]
});
evaluateChart.hideLoading();
});
}
});

@ -0,0 +1,7 @@
.admins-dashboards-index-page {
.pie-statistic {
.pie {
height: 300px;
}
}
}

@ -1,4 +1,50 @@
class Admins::DashboardsController < Admins::BaseController
def index
@active_user_count = User.where(last_login_on: today).count
@weekly_active_user_count = User.where(last_login_on: current_week).count
@month_active_user_count = User.where(last_login_on: current_month).count
@new_user_count = User.where(created_on: current_month).count
end
def month_active_user
count = UserExtension.where(created_at: current_month).group(:identity).count
data = [
{ value: count['teacher'].to_i, name: '老师' },
{ value: count['student'].to_i, name: '学生' },
{ value: count['professional'].to_i, name: '专业人士' }
]
render_ok(data: data)
end
def evaluate
names = []
data = []
7.times do |i|
date = i.days.ago
names.unshift(date.strftime('%Y-%m-%d'))
count = Output.where(created_at: date.beginning_of_day..date.end_of_day).count
data.unshift(count)
end
render_ok(names: names, data: data)
end
private
def today
Time.now.beginning_of_day..Time.now.end_of_day
end
def current_week
7.days.ago.beginning_of_day..Time.now.end_of_day
end
def current_month
30.days.ago.beginning_of_day..Time.now.end_of_day
end
end

@ -3,21 +3,21 @@ class ShixunsController < ApplicationController
include ApplicationHelper
before_action :require_login, :check_auth, except: [:download_file, :index, :menus, :show, :show_right, :ranking_list,
:discusses, :collaborators, :fork_list, :propaedeutics, :add_file]
:discusses, :collaborators, :fork_list, :propaedeutics]
before_action :check_account, only: [:new, :create, :shixun_exec]
before_action :find_shixun, except: [:index, :new, :create, :menus, :get_recommend_shixuns,
:propaedeutics, :departments, :apply_shixun_mirror,
:get_mirror_script, :download_file]
before_action :shixun_access_allowed, except: [:index, :new, :create, :menus, :get_recommend_shixuns, :add_file,
before_action :shixun_access_allowed, except: [:index, :new, :create, :menus, :get_recommend_shixuns,
:propaedeutics, :departments, :apply_shixun_mirror,
:get_mirror_script, :download_file]
before_action :find_repo_name, only: [:repository, :commits, :file_content, :update_file, :shixun_exec, :copy, :add_file]
before_action :allowed, only: [:update, :close, :update_propaedeutics, :settings, :publish,
:shixun_members_added, :change_manager, :collaborators_delete,
:cancel_publish, :add_collaborators]
:cancel_publish, :add_collaborators, :add_file]
before_action :portion_allowed, only: [:copy]
before_action :special_allowed, only: [:send_to_course, :search_user_courses]

@ -12,19 +12,19 @@
<div class="card-body">
<div class="row">
<div class="col">
<h5 class="card-title text-uppercase text-muted mb-0">Traffic</h5>
<span class="h2 font-weight-bold mb-0">350,897</span>
<h5 class="card-title text-uppercase text-muted mb-0">当日活跃用户</h5>
<span class="h2 font-weight-bold mb-0"><%= @active_user_count %></span>
</div>
<div class="col-auto">
<div class="icon icon-shape bg-danger text-white rounded-circle shadow">
<i class="fas fa-pie-chart"></i>
<div class="icon icon-shape rounded-circle shadow">
<i class="fa fa-users"></i>
</div>
</div>
</div>
<p class="mt-3 mb-0 text-muted text-sm">
<span class="text-success mr-2"><i class="fa fa-arrow-up"></i> 3.48%</span>
<span class="text-nowrap">Since last month</span>
</p>
<!-- <p class="mt-3 mb-0 text-muted text-sm">-->
<!-- <span class="text-success mr-2"><i class="fa fa-arrow-up"></i> 3.48%</span>-->
<!-- <span class="text-nowrap">Since last month</span>-->
<!-- </p>-->
</div>
</div>
</div>
@ -33,19 +33,19 @@
<div class="card-body">
<div class="row">
<div class="col">
<h5 class="card-title text-uppercase text-muted mb-0">New users</h5>
<span class="h2 font-weight-bold mb-0">2,356</span>
<h5 class="card-title text-uppercase text-muted mb-0">7天内活跃用户数</h5>
<span class="h2 font-weight-bold mb-0"><%= @weekly_active_user_count %></span>
</div>
<div class="col-auto">
<div class="icon icon-shape bg-warning text-white rounded-circle shadow">
<i class="fas fa-pie-chart"></i>
<div class="icon icon-shape rounded-circle shadow">
<i class="fa fa-users"></i>
</div>
</div>
</div>
<p class="mt-3 mb-0 text-muted text-sm">
<span class="text-danger mr-2"><i class="fas fa-arrow-down"></i> 3.48%</span>
<span class="text-nowrap">Since last week</span>
</p>
<!-- <p class="mt-3 mb-0 text-muted text-sm">-->
<!-- <span class="text-danger mr-2"><i class="fas fa-arrow-down"></i> 3.48%</span>-->
<!-- <span class="text-nowrap">Since last week</span>-->
<!-- </p>-->
</div>
</div>
</div>
@ -54,19 +54,19 @@
<div class="card-body">
<div class="row">
<div class="col">
<h5 class="card-title text-uppercase text-muted mb-0">Sales</h5>
<span class="h2 font-weight-bold mb-0">924</span>
<h5 class="card-title text-uppercase text-muted mb-0">30天内活跃用户数</h5>
<span class="h2 font-weight-bold mb-0"><%= @month_active_user_count %></span>
</div>
<div class="col-auto">
<div class="icon icon-shape bg-yellow text-white rounded-circle shadow">
<i class="fas fa-user"></i>
<div class="icon icon-shape rounded-circle shadow">
<i class="fa fa-users"></i>
</div>
</div>
</div>
<p class="mt-3 mb-0 text-muted text-sm">
<span class="text-warning mr-2"><i class="fas fa-arrow-down"></i> 1.10%</span>
<span class="text-nowrap">Since yesterday</span>
</p>
<!-- <p class="mt-3 mb-0 text-muted text-sm">-->
<!-- <span class="text-warning mr-2"><i class="fas fa-arrow-down"></i> 1.10%</span>-->
<!-- <span class="text-nowrap">Since yesterday</span>-->
<!-- </p>-->
</div>
</div>
</div>
@ -75,19 +75,19 @@
<div class="card-body">
<div class="row">
<div class="col">
<h5 class="card-title text-uppercase text-muted mb-0">Performance</h5>
<span class="h2 font-weight-bold mb-0">49,65%</span>
<h5 class="card-title text-uppercase text-muted mb-0">30天内新增用户数</h5>
<span class="h2 font-weight-bold mb-0"><%= @new_user_count %></span>
</div>
<div class="col-auto">
<div class="icon icon-shape bg-info text-white rounded-circle shadow">
<i class="fas fa-pie-chart"></i>
<div class="icon icon-shape rounded-circle shadow">
<i class="fa fa-user-plus"></i>
</div>
</div>
</div>
<p class="mt-3 mb-0 text-muted text-sm">
<span class="text-success mr-2"><i class="fas fa-arrow-up"></i> 12%</span>
<span class="text-nowrap">Since last month</span>
</p>
<!-- <p class="mt-3 mb-0 text-muted text-sm">-->
<!-- <span class="text-success mr-2"><i class="fas fa-arrow-up"></i> 12%</span>-->
<!-- <span class="text-nowrap">Since last month</span>-->
<!-- </p>-->
</div>
</div>
</div>
@ -95,94 +95,124 @@
</div>
</div>
</div>
<div class="container-fluid mt--7">
<div class="container-fluid mt--7 pie-statistic">
<div class="row mt-5">
<div class="col-xl-8 mb-5 mb-xl-0">
<div class="card shadow">
<div class="card-header border-0">
<div class="row align-items-center">
<div class="col">
<h3 class="mb-0">Page visits</h3>
</div>
<div class="col text-right">
<a href="#!" class="btn btn-sm btn-primary">Test</a>
</div>
<h5 class="mb-0">近7天评测次数</h5>
</div>
</div>
<div class="table-responsive">
<!-- Projects table -->
<table class="table align-items-center table-flush">
<thead class="thead-light">
<tr>
<th scope="col">Test</th>
<th scope="col">Test</th>
<th scope="col">Test</th>
<th scope="col">Test</th>
</tr>
</thead>
<tbody>
<% 5.times do %>
<tr>
<th scope="row">/test/</th>
<td>4,569</td>
<td>340</td>
<td>
<i class="fas fa-arrow-up text-success mr-3"></i> 46,53%
</td>
</tr>
<% end %>
</tbody>
</table>
<div id="evaluate-pie" class="pie"></div>
</div>
</div>
</div>
<div class="col-xl-4">
<div class="card shadow">
<div class="card-header border-0">
<div class="row align-items-center">
<div class="col">
<h3 class="mb-0">Test</h3>
</div>
<div class="col text-right">
<a href="#!" class="btn btn-sm btn-primary">Test</a>
</div>
<h5 class="mb-0">30天内新增用户</h5>
</div>
</div>
<div class="table-responsive">
<!-- Projects table -->
<table class="table align-items-center table-flush">
<thead class="thead-light">
<tr>
<th scope="col">Test</th>
<th scope="col">Test</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
<% 5.times do %>
<tr>
<th scope="row">
Test
</th>
<td>
1,480
</td>
<td>
<div class="d-flex align-items-center">
<span class="mr-2">60%</span>
<div>
<div class="progress">
<div class="progress-bar bg-gradient-danger" role="progressbar" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100" style="width: 60%;"></div>
</div>
</div>
</div>
</td>
</tr>
<% end %>
</tbody>
</table>
<div id="month-active-user" class="pie"></div>
</div>
</div>
</div>
</div>
</div>
<!--<div class="container-fluid mt--7">-->
<!-- <div class="row mt-5">-->
<!-- <div class="col-xl-8 mb-5 mb-xl-0">-->
<!-- <div class="card shadow">-->
<!-- <div class="card-header border-0">-->
<!-- <div class="row align-items-center">-->
<!-- <div class="col">-->
<!-- <h3 class="mb-0">Page visits</h3>-->
<!-- </div>-->
<!-- <div class="col text-right">-->
<!-- <a href="#!" class="btn btn-sm btn-primary">Test</a>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- <div class="table-responsive">-->
<!-- <table class="table align-items-center table-flush">-->
<!-- <thead class="thead-light">-->
<!-- <tr>-->
<!-- <th scope="col">Test</th>-->
<!-- <th scope="col">Test</th>-->
<!-- <th scope="col">Test</th>-->
<!-- <th scope="col">Test</th>-->
<!-- </tr>-->
<!-- </thead>-->
<!-- <tbody>-->
<%# 5.times do %>
<!-- <tr>-->
<!-- <th scope="row">/test/</th>-->
<!-- <td>4,569</td>-->
<!-- <td>340</td>-->
<!-- <td>-->
<!-- <i class="fas fa-arrow-up text-success mr-3"></i> 46,53%-->
<!-- </td>-->
<!-- </tr>-->
<%# end %>
<!-- </tbody>-->
<!-- </table>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- <div class="col-xl-4">-->
<!-- <div class="card shadow">-->
<!-- <div class="card-header border-0">-->
<!-- <div class="row align-items-center">-->
<!-- <div class="col">-->
<!-- <h3 class="mb-0">Test</h3>-->
<!-- </div>-->
<!-- <div class="col text-right">-->
<!-- <a href="#!" class="btn btn-sm btn-primary">Test</a>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- <div class="table-responsive">-->
<!-- <table class="table align-items-center table-flush">-->
<!-- <thead class="thead-light">-->
<!-- <tr>-->
<!-- <th scope="col">Test</th>-->
<!-- <th scope="col">Test</th>-->
<!-- <th scope="col"></th>-->
<!-- </tr>-->
<!-- </thead>-->
<!-- <tbody>-->
<%# 5.times do %>
<!-- <tr>-->
<!-- <th scope="row">-->
<!-- Test-->
<!-- </th>-->
<!-- <td>-->
<!-- 1,480-->
<!-- </td>-->
<!-- <td>-->
<!-- <div class="d-flex align-items-center">-->
<!-- <span class="mr-2">60%</span>-->
<!-- <div>-->
<!-- <div class="progress">-->
<!-- <div class="progress-bar bg-gradient-danger" role="progressbar" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100" style="width: 60%;"></div>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- </td>-->
<!-- </tr>-->
<%# end %>
<!-- </tbody>-->
<!-- </table>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!--</div>-->

@ -779,6 +779,12 @@ Rails.application.routes.draw do
namespace :admins do
get '/', to: 'dashboards#index'
resources :dashboards, only: [:index] do
collection do
get :month_active_user
get :evaluate
end
end
resources :files, only: [:create]
resources :daily_school_statistics, only: [:index] do

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -37,7 +37,7 @@ class ShixunChooseModal extends Component{
hometypepvisible:loading
})
let coursesId=this.props.match.params.coursesId;
let url ="/courses/"+coursesId+"/homework_commons/shixuns.json";
let url = this.props.shixunsUrl || "/courses/"+coursesId+"/homework_commons/shixuns.json";
axios.get(url, {
params: {
@ -76,7 +76,7 @@ class ShixunChooseModal extends Component{
})
let coursesId=this.props.match.params.coursesId;
let url ="/courses/"+coursesId+"/homework_commons/shixuns.json";
let url = this.props.shixunsUrl || "/courses/"+coursesId+"/homework_commons/shixuns.json";
axios.get(url).then((result)=>{
if(result.status===200){

@ -25,7 +25,7 @@ class ShixunModal extends Component{
hometypepvisible:true,
})
let coursesId=this.props.match.params.coursesId;
let url ="/courses/"+coursesId+"/homework_commons/shixuns.json";
let url = this.props.shixunsUrl || "/courses/"+coursesId+"/homework_commons/shixuns.json";
axios.get(url).then((result)=>{
if(result.status===200){
@ -51,7 +51,7 @@ class ShixunModal extends Component{
hometypepvisible:loading
})
let coursesId=this.props.match.params.coursesId;
let url ="/courses/"+coursesId+"/homework_commons/shixuns.json";
let url = this.props.shixunsUrl || "/courses/"+coursesId+"/homework_commons/shixuns.json";
axios.get(url, {
params: {

@ -5,440 +5,63 @@ import {
Slider, Button, Upload, Icon, Rate, Checkbox, message,
Row, Col, Select, Modal, Tooltip
} from 'antd';
import { Q_TYPE_SINGLE, Q_TYPE_MULTI, Q_TYPE_JUDGE, Q_TYPE_NULL, Q_TYPE_MAIN, Q_TYPE_SHIXUN } from './new/common'
import TPMMDEditor from '../../tpm/challengesnew/TPMMDEditor';
import axios from 'axios'
// import './board.css'
import "../common/formCommon.css"
// import "../common/formCommon.css"
// import { RouteHOC } from './common.js'
import CBreadcrumb from '../common/CBreadcrumb'
import {getUrl, ActionBtn} from 'educoder';
import SingleEditor from './new/SingleEditor'
import SingleDisplay from './new/SingleDisplay'
import JudgeEditor from './new/JudgeEditor'
import JudgeDisplay from './new/JudgeDisplay'
import NullEditor from './new/NullEditor'
import NullDisplay from './new/NullDisplay'
import MainEditor from './new/MainEditor'
import MainDisplay from './new/MainDisplay'
import ShixunEditor from './new/ShixunEditor'
import ShixunDisplay from './new/ShixunDisplay'
// import { Q_TYPE_SINGLE, Q_TYPE_MULTI, Q_TYPE_JUDGE, Q_TYPE_NULL, Q_TYPE_MAIN, Q_TYPE_SHIXUN } from './new/common'
// import TPMMDEditor from '../../tpm/challengesnew/TPMMDEditor';
// import CBreadcrumb from '../common/CBreadcrumb'
import {getUrl, ActionBtn, CBreadcrumb} from 'educoder';
// import SingleEditor from './new/SingleEditor'
// import SingleDisplay from './new/SingleDisplay'
// import JudgeEditor from './new/JudgeEditor'
// import JudgeDisplay from './new/JudgeDisplay'
// import NullEditor from './new/NullEditor'
// import NullDisplay from './new/NullDisplay'
// import MainEditor from './new/MainEditor'
// import MainDisplay from './new/MainDisplay'
// import ShixunEditor from './new/ShixunEditor'
// import ShixunDisplay from './new/ShixunDisplay'
import ShixunChooseModal from '../coursesPublic/ShixunChooseModal'
import update from 'immutability-helper'
import './new/common.css'
import '../css/Courses.css'
import ExerciseNewCommon from './ExerciseNewCommon'
const { TextArea } = Input;
const confirm = Modal.confirm;
const $ = window.$
const { Option } = Select;
const TITLE_MAX_LENGTH = 60;
class ExerciceNew extends Component{
constructor(props){
super(props);
this.state = {
exercise_questions: [],
exercise_name: '',
exercise_description: '',
exercise_types: {},
editMode: !this.props.match.params.Id,
}
}
// 已发布试卷编辑保存的确认弹框
changeScore = (question_id,answerArray) =>{
this.props.confirm({
content:'修改了标准答案',
subContent:"是否重新计算学生答题的成绩?",
onOk:()=>{
this.sureChangeScore(question_id,answerArray)
},
onCancel:()=>{
this.addSuccess();
}
})
}
// 已发布试卷修改答案确认修改分数
sureChangeScore = (question_id,answerArray) =>{
let url=`/exercise_questions/${question_id}/update_scores.json`
axios.post((url),{
standard_answers:answerArray
}).then((result)=>{
if(result){
this.props.showNotification(`${result.data.message}`);
this.addSuccess();
}
}).catch((error)=>{
console.log(error);
})
}
fetchExercise = () => {
const Id = this.props.match.params.Id
this.isEdit = !!Id
if (Id) {
const url = `/exercises/${Id}/edit.json`
axios.get(url)
.then((response) => {
if (response.data.status == 0) {
const { exercise, ...others } = response.data
this.setState({
...exercise,
...others,
editMode: false
})
}
})
.catch(function (error) {
console.log(error);
});
} else {
const courseId=this.props.match.params.coursesId;
const newUrl = `/courses/${courseId}/exercises/new.json`
axios.get(newUrl)
.then((response) => {
if (response.data.status == 0) {
this.setState({
...response.data
})
}
})
.catch(function (error) {
console.log(error);
});
}
}
componentDidMount = () => {
this.fetchExercise()
}
handleSubmit = (e) => {
}
onSaveExercise = () => {
const { exercise_name, exercise_description } = this.state;
const exercise_id = this.props.match.params.Id
const courseId = this.props.match.params.coursesId
if (this.isEdit) {
const editUrl = `/exercises/${exercise_id}.json`
axios.put(editUrl, {
exercise_name,
exercise_description
})
.then((response) => {
if (response.data.status == 0) {
this.setState({editMode: false})
this.props.showNotification('试卷编辑成功')
}
})
.catch(function (error) {
console.log(error);
});
} else {
const url = `/courses/${courseId}/exercises.json`
axios.post(url, {
exercise_name,
exercise_description
})
.then((response) => {
if (response.data.status == 0) {
this.setState({editMode: false})
this.props.showNotification('试卷新建成功')
const exercise_id = response.data.data.exercise_id;
this.isEdit = true;
this.props.history.replace(`/courses/${courseId}/exercises/${exercise_id}/edit`);
}
})
.catch(function (error) {
console.log(error);
});
}
}
exercise_name_change = (e) => {
this.setState({exercise_name: e.target.value})
}
exercise_description_change = (e) => {
this.setState({exercise_description: e.target.value})
}
// #问题的类型0为单选题1为多选题2为判断题3为填空题4为主观题5为实训题
_checkIsEditing = () => {
if (this.editingId && $(this.editingId).length ) {
this.props.showNotification('请先保存或取消当前正在编辑的问题。')
$("html").animate({ scrollTop: $(this.editingId).offset().top - 100})
return true
}
return false
}
onEditorCancel = () => {
this.editingId = null;
// 找到编辑或新建的item新建就删掉item编辑就isNew改为false
const { exercise_questions } = this.state
let index = -1;
for(let i = 0; i < exercise_questions.length; i++) {
if (exercise_questions[i].isNew == true) {
index = i;
break;
}
}
if (exercise_questions[index].question_id) { // 编辑
this.setState(
(prevState) => ({
exercise_questions : update(prevState.exercise_questions, {[index]: { isNew: {$set: false}}})
// update(prevState.exercise_questions, {$splice: [[index, 1]]})
})
)
} else { // 新建
this.setState(
(prevState) => ({
exercise_questions : update(prevState.exercise_questions, {$splice: [[index, 1]]})
})
)
}
}
addQuestion = (question_id_to_insert_after, type) => {
if (!this.isEdit) {
this.props.showNotification('请先输入试卷标题,并保存试卷')
return;
}
if (this._checkIsEditing()) {
return;
}
if (type == Q_TYPE_SHIXUN) {
this.addShixun(question_id_to_insert_after)
} else {
this.addEditingQuestion(type, question_id_to_insert_after)
}
}
chooseShixun = (array) => {
this.addEditingQuestion(Q_TYPE_SHIXUN, this.question_id_to_insert_after, {
shixun_id: array[0]
})
}
chooseShixunSuccess = () => {
this.refs.shixunChooseModal.setVisible(false)
}
addShixun = (question_id_to_insert_after) => {
if (!this.isEdit) {
this.props.showNotification('请先输入试卷标题,并保存试卷')
return;
}
// TODO 弹框选择实训
if (this._checkIsEditing()) {
return;
}
this.refs.shixunChooseModal.setVisible(true)
this.question_id_to_insert_after = question_id_to_insert_after;
return;
// 拉取实训items
this.addEditingQuestion(Q_TYPE_SHIXUN, question_id_to_insert_after, {
shixun_id: 50
})
}
editQestion = (index) => {
if (this._checkIsEditing()) {
return;
}
this.editingId = `#question_${index}`
this.setState(
(prevState) => ({
exercise_questions : update(prevState.exercise_questions, {[index]: { isNew: {$set: true}}})
})
)
}
onSort = (index, question_id, isUp) => {
if (this._checkIsEditing()) {
return;
}
const url = `/exercise_questions/${question_id}/up_down.json`
axios.post(url, { opr: isUp ? 'up' : 'down'})
.then((response) => {
if (response.data.status == 0) {
// this.props.showNotification('移动成功')
this.fetchExercise()
}
})
.catch(function (error) {
console.log(error);
});
}
onSortDown = (index, question_id) => {
this.onSort(index, question_id, false)
}
onSortUp = (index, question_id) => {
this.onSort(index, question_id, true)
}
getInitScore = (question_type, question_id_to_insert_after) => {
/**
1.每个题型的首个题目默认值规则如下
选择题5 01
判断题2 2
填空题2 3
简答题10 4
实训题每个关卡5分 5
*/
let init_question_score = 0;
if (question_type == 0 || question_type == 1) {
init_question_score = 5
} else if (question_type == 2) {
init_question_score = 2
} else if (question_type == 3) {
init_question_score = 2
} else if (question_type == 4) {
init_question_score = 10
} else if (question_type == 5) {
init_question_score = 5
}
const _indexBefore = question_id_to_insert_after ? this.findIndexById(question_id_to_insert_after) : this.state.exercise_questions.length - 1
for (let i = _indexBefore; i >= 0; i--) {
if(this.state.exercise_questions[i].question_type == question_type) {
init_question_score = this.state.exercise_questions[i].question_score
break;
}
}
return init_question_score;
}
addEditingQuestion = (question_type, question_id_to_insert_after, otherAttributes) => {
let init_question_score = this.getInitScore(question_type, question_id_to_insert_after)
let questionObj = {
question_type: question_type, // 需要这个通过类型判断
init_question_score: init_question_score,
isNew: true, // 新建或编辑用是否有id区分是新建还是编辑
question_id_to_insert_after,
...otherAttributes
}
const { exercise_questions } = this.state;
let new_exercise_questions = exercise_questions.slice(0)
let newIndex = new_exercise_questions.length;
if (question_id_to_insert_after) {
const _indexBefore = this.findIndexById(question_id_to_insert_after)
new_exercise_questions.splice(_indexBefore + 1, 0, questionObj)
newIndex = _indexBefore + 1
} else {
new_exercise_questions.push(questionObj)
}
this.editingId = `#question_${newIndex}`
this.setState({ exercise_questions: new_exercise_questions }, () => {
setTimeout(() => {
$(this.editingId).length && $("html").animate({ scrollTop: $(this.editingId).offset().top - 100})
}, 500)
})
}
findIndexById = (id) => {
const { exercise_questions } = this.state
for(let i = 0; i < exercise_questions.length; i++) {
if (exercise_questions[i].question_id == id) {
return i;
}
}
}
onQestionDelete = (question_id) => {
this.props.confirm({
content: `确认要删除这个问题吗?`,
onOk: () => {
const url = `/exercise_questions/${question_id}.json`
axios.delete(url)
.then((response) => {
if (response.data.status == 0) {
this.props.showNotification('删除成功')
this.fetchExercise()
// const { exercise_questions } = this.state
// const index = this.findIndexById(question_id)
// this.setState(
// (prevState) => ({
// exercise_questions : update(prevState.exercise_questions, {$splice: [[index, 1]]})
// })
// )
}
})
.catch(function (error) {
console.log(error);
});
}
})
}
addSuccess = () => {
this.editingId = null;
this.fetchExercise()
}
goToPreview = () => {
const exercise_id = this.props.match.params.Id
const courseId = this.props.match.params.coursesId
this.props.history.push(`/courses/${courseId}/exercises/${exercise_id}/student_exercise_list?tab=2`)
initData = (data) => {
this.setState({left_banner_id: data.left_banner_id})
}
render() {
let { exercise_name, exercise_description, course_id, exercise_types,
exercise_questions, left_banner_id } = this.state;
// if (this.isEdit && !exercise_types) {
// return ''
// }
// const { getFieldDecorator } = this.props.form;
const { q_counts, q_scores, q_doubles, q_doubles_scores, q_judges, q_judges_scores,
q_mains, q_mains_scores, q_nulls, q_nulls_scores, q_shixuns, q_shixuns_scores, q_singles, q_singles_scores} = exercise_types;
const formItemLayout = {
labelCol: {
xs: { span: 24 },
// sm: { span: 8 },
sm: { span: 24 },
},
wrapperCol: {
xs: { span: 24 },
// sm: { span: 16 },
sm: { span: 24 },
},
};
let { left_banner_id } = this.state;
const { current_user } = this.props
const isAdmin = this.props.isAdmin()
const courseId=this.props.match.params.coursesId;
const exercise_id = this.props.match.params.Id
const isEdit = this.isEdit
const commonHandler = {
onQestionDelete: this.onQestionDelete,
addSuccess: this.addSuccess,
addQuestion: this.addQuestion,
onEditorCancel: this.onEditorCancel,
changeScore:this.changeScore,
editQestion: this.editQestion,
onSortDown: this.onSortDown,
onSortUp: this.onSortUp,
displayCount: exercise_questions.length,
exercise_status: this.state.exercise_status,
exerciseIsPublish: this.state.exercise_status >= 2
}
return(
<div className="newMain exerciseNew">
<ShixunChooseModal
ref="shixunChooseModal"
chooseShixun={this.chooseShixun}
{...this.props}
singleChoose={true}
></ShixunChooseModal>
<style>{`
.courseForm .formBlock {
padding: 20px 30px 30px 30px;
border-bottom: 1px solid #EDEDED;
margin-bottom: 0px;
background: #fff;
}
.exerciseNew .markdown-body {
max-width: 1128px;
}
`}</style>
<div className="edu-class-container edu-position courseForm">
{ current_user && <CBreadcrumb items={[
{ to: current_user&&current_user.first_category_url, name: this.props.coursedata ? this.props.coursedata.name : ''},
@ -455,160 +78,12 @@ class ExerciceNew extends Component{
</a>
</p>
{!this.state.editMode && <div className="padding20-30" style={{ background: '#fff'}}>
<div className="displayTitle font-16">
<span>{exercise_name}</span>
<a className="fr mr6" onClick={() => { this.setState({editMode: true}) }} style={{ lineHeight: '32px'}}>
<Tooltip title="编辑"><i className="iconfont icon-bianjidaibeijing font-20 color-green"></i></Tooltip>
</a>
</div>
<div className="displayDescription color-grey-9" dangerouslySetInnerHTML={{__html: exercise_description}}
style={{whiteSpace: 'pre-wrap'}}
></div>
</div>}
{this.state.editMode && <Form {...formItemLayout} onSubmit={this.handleSubmit}>
<div className="formBlock" style={{paddingBottom: '2px',borderBottom:"none"}}>
<Form.Item
label="试卷标题"
required
className="topicTitle "
>
{/* {getFieldDecorator('subject', {
rules: [{
required: true, message: '请输入标题',
}, {
max: 20, message: '最大限制为20个字符',
}],
})( */}
<style>
{
`
.exercicenewinputysl .ant-input{
border-right: none !important;
height: 40px !important;
}
`
}
</style>
<Input placeholder={`请输入试卷标题,最大限制${TITLE_MAX_LENGTH}个字符`} maxLength={TITLE_MAX_LENGTH} className="mt5 exercicenewinputysl" value={exercise_name}
onChange={this.exercise_name_change} addonAfter={`${exercise_name ? exercise_name.length : 0}/${TITLE_MAX_LENGTH}`}
/>
{/* )} */}
</Form.Item>
<Form.Item
label="&nbsp;&nbsp;试卷须知"
>
{/* {getFieldDecorator('select_board_id', {
// initialValue: '3779',
})( */}
<TextArea placeholder="请在此输入本次试卷答题的相关说明最大限制100个字符" className="mt5" style={{height:"120px"}} value={exercise_description}
onChange={this.exercise_description_change}
/>
{/* )} */}
</Form.Item>
<Form.Item>
{/* defalutSubmitbtn */}
<a className="task-btn task-btn-orange fr mt4" style={{height: '30px', width: '70px'}}
onClick={this.onSaveExercise}
>保存</a>
{ this.isEdit && <a onClick={() => this.setState({editMode: false})} className="defalutCancelbtn fr mt4"
style={{height: '30px', width: '70px', fontSize: '14px', lineHeight: '30px', marginRight: '16px'}}>取消</a>}
{/* <Button type="primary" onClick={this.onSaveExercise} className="fr">保存</Button> */}
</Form.Item>
</div>
{/* <div className="clearfix mt30 mb30">
<a className="defalutCancelbtn fl" onClick={() => {}}>取消</ a>
</div> */}
</Form>}
<p className="clearfix padding20-30 color-grey-9">
<span className="fl">
{ !!q_singles && <span className="mr20">单选题{q_singles}{q_singles_scores}</span>}
{ !!q_doubles && <span className="mr20">多选题{q_doubles}{q_doubles_scores}</span>}
{ !!q_judges && <span className="mr20">判断题{q_judges}{q_judges_scores}</span>}
{ !!q_nulls && <span className="mr20">填空题{q_nulls}{q_nulls_scores}</span>}
{ !!q_mains && <span className="mr20">简答题{q_mains}{q_mains_scores}</span>}
{ !!q_shixuns && <span className="mr20">实训题{q_shixuns}{q_shixuns_scores}</span> }
</span>
<span className="fr">
{ !!q_counts &&
<span>
合计 <span className="color-blue">{q_counts}</span>
<span className={`${q_scores > 100 ? 'color-red font-bd' : 'color-orange'}`}>{q_scores}</span>
</span>
}
</span>
</p>
<div className="edu-back-white">
{ exercise_questions.map((item, index) => {
if (item.question_type == 0 || item.question_type == 1) {
if (item.isNew) {
return <SingleEditor {...this.props} {...item} index={index} {...commonHandler}></SingleEditor>
} else {
return <SingleDisplay {...this.props} {...item} index={index} {...commonHandler}
displayCount={exercise_questions.length}
></SingleDisplay>
}
} else if (item.question_type == 2) {
if (item.isNew) {
return <JudgeEditor {...this.props} {...item} index={index} {...commonHandler}></JudgeEditor>
} else {
return <JudgeDisplay {...this.props} {...item} index={index} {...commonHandler} ></JudgeDisplay>
}
} else if (item.question_type == 3) {
if (item.isNew) {
return <NullEditor {...this.props} {...item} index={index} {...commonHandler}></NullEditor>
} else {
return <NullDisplay {...this.props} {...item} index={index} {...commonHandler} ></NullDisplay>
}
} else if (item.question_type == 4) {
if (item.isNew) {
return <MainEditor {...this.props} {...item} index={index} {...commonHandler} ></MainEditor>
} else {
return <MainDisplay {...this.props} {...item} index={index} {...commonHandler} ></MainDisplay>
}
} else if (item.question_type == 5) {
if (item.isNew) {
return <ShixunEditor {...this.props} {...item} index={index} {...commonHandler}
chooseShixunSuccess={this.chooseShixunSuccess}
></ShixunEditor>
} else {
return <ShixunDisplay {...this.props} {...item} index={index} {...commonHandler} ></ShixunDisplay>
}
}
return <div></div>
})}
{!commonHandler.exerciseIsPublish && <div className="problemShow padding30">
<ActionBtn style="green" className="mr20" onClick={() => this.addQuestion(null, Q_TYPE_SINGLE)}>
<i className="iconfont icon-tianjiafangda color-white font-14 mr5" style={{ marginTop: '-1px', display: 'inline-block'}}></i>
</ActionBtn>
<ActionBtn style="green" className="mr20" onClick={() => this.addQuestion(null, Q_TYPE_JUDGE)}>
<i className="iconfont icon-tianjiafangda color-white font-14 mr5" style={{ marginTop: '-1px', display: 'inline-block'}}></i>
</ActionBtn>
<ActionBtn style="green" className="mr20" onClick={() => this.addQuestion(null, Q_TYPE_NULL)}>
<i className="iconfont icon-tianjiafangda color-white font-14 mr5" style={{ marginTop: '-1px', display: 'inline-block'}}></i>
</ActionBtn>
<ActionBtn style="green" className="mr20" onClick={() => this.addQuestion(null, Q_TYPE_MAIN)}>
<i className="iconfont icon-tianjiafangda color-white font-14 mr5" style={{ marginTop: '-1px', display: 'inline-block'}}></i>
</ActionBtn>
<ActionBtn style="green" className="mr20" onClick={() => this.addShixun(null)}>
<i className="iconfont icon-tianjiafangda color-white font-14 mr5" style={{ marginTop: '-1px', display: 'inline-block'}}></i>
</ActionBtn>
{exercise_id && <ActionBtn style="blue" className="fr" onClick={() => this.goToPreview()}>
{/* <i className="iconfont icon-tianjiafangda color-white font-14 mr5" style={{ marginTop: '-1px', display: 'inline-block'}}></i> */}
试卷预览
</ActionBtn>}
</div>}
</div>
<ExerciseNewCommon
{...this.props}
{...this.state}
isEdit={this.isEdit}
initData={this.initData}
></ExerciseNewCommon>
</div>
</div>
)

@ -0,0 +1,619 @@
import React,{ Component } from "react";
import {
Form, Input, InputNumber, Switch, Radio,
Slider, Button, Upload, Icon, Rate, Checkbox, message,
Row, Col, Select, Modal, Tooltip
} from 'antd';
import { Q_TYPE_SINGLE, Q_TYPE_MULTI, Q_TYPE_JUDGE, Q_TYPE_NULL, Q_TYPE_MAIN, Q_TYPE_SHIXUN } from './new/common'
import TPMMDEditor from '../../tpm/challengesnew/TPMMDEditor';
import axios from 'axios'
// import './board.css'
import "../common/formCommon.css"
// import { RouteHOC } from './common.js'
import CBreadcrumb from '../common/CBreadcrumb'
import {getUrl, ActionBtn} from 'educoder';
import SingleEditor from './new/SingleEditor'
import SingleDisplay from './new/SingleDisplay'
import JudgeEditor from './new/JudgeEditor'
import JudgeDisplay from './new/JudgeDisplay'
import NullEditor from './new/NullEditor'
import NullDisplay from './new/NullDisplay'
import MainEditor from './new/MainEditor'
import MainDisplay from './new/MainDisplay'
import ShixunEditor from './new/ShixunEditor'
import ShixunDisplay from './new/ShixunDisplay'
import ShixunChooseModal from '../coursesPublic/ShixunChooseModal'
import update from 'immutability-helper'
import './new/common.css'
import '../css/Courses.css'
const { TextArea } = Input;
const confirm = Modal.confirm;
const $ = window.$
const { Option } = Select;
const TITLE_MAX_LENGTH = 60;
class ExerciseNewCommon extends Component{
constructor(props){
super(props);
this.state = {
exercise_questions: [],
exercise_name: '',
exercise_description: '',
exercise_types: {},
editMode: !this.props.match.params.Id,
}
}
// 已发布试卷编辑保存的确认弹框
changeScore = (question_id,answerArray) =>{
this.props.confirm({
content:'修改了标准答案',
subContent:"是否重新计算学生答题的成绩?",
onOk:()=>{
this.sureChangeScore(question_id,answerArray)
},
onCancel:()=>{
this.addSuccess();
}
})
}
// 已发布试卷修改答案确认修改分数
sureChangeScore = (question_id,answerArray) =>{
let url=`/exercise_questions/${question_id}/update_scores.json`
axios.post((url),{
standard_answers:answerArray
}).then((result)=>{
if(result){
this.props.showNotification(`${result.data.message}`);
this.addSuccess();
}
}).catch((error)=>{
console.log(error);
})
}
fetchExercise = () => {
const Id = this.props.match.params.Id
this.isEdit = this.props.isEdit || !!Id
if (this.isEdit) {
const url = this.props.exercise_url ? `/${this.props.exercise_url }/${Id}.json` : `/exercises/${Id}/edit.json`
axios.get(url)
.then((response) => {
if (response.data.exercise) {
const { exercise, ...others } = response.data
exercise.exercise_name = exercise.exercise_name || exercise.name
exercise.exercise_description = exercise.exercise_description || exercise.description
this.setState({
...exercise,
...others,
editMode: false
})
this.props.initData && this.props.initData(response.data)
}
})
.catch(function (error) {
console.log(error);
});
} else {
const courseId=this.props.match.params.coursesId;
const newUrl = `/courses/${courseId}/exercises/new.json`
axios.get(newUrl)
.then((response) => {
if (response.data.status == 0) {
this.setState({
...response.data
})
}
})
.catch(function (error) {
console.log(error);
});
}
}
componentDidMount = () => {
this.fetchExercise()
}
handleSubmit = (e) => {
}
onSaveExercise = () => {
const { exercise_name, exercise_description } = this.state;
const exercise_id = this.props.match.params.Id
const courseId = this.props.match.params.coursesId
if (this.isEdit) {
// /exercise_banks/:id.json
const editUrl = `/${this.props.exercise_url ? this.props.exercise_url : 'exercises'}/${exercise_id}.json`
axios.put(editUrl, {
exercise_name,
exercise_description
})
.then((response) => {
if (response.data.status == 0) {
this.setState({editMode: false})
this.props.showNotification('试卷编辑成功')
}
})
.catch(function (error) {
console.log(error);
});
} else {
const url = `/courses/${courseId}/exercises.json`
axios.post(url, {
exercise_name,
exercise_description
})
.then((response) => {
if (response.data.status == 0) {
this.setState({editMode: false})
this.props.showNotification('试卷新建成功')
const exercise_id = response.data.data.exercise_id;
this.isEdit = true;
this.props.history.replace(`/courses/${courseId}/exercises/${exercise_id}/edit`);
}
})
.catch(function (error) {
console.log(error);
});
}
}
exercise_name_change = (e) => {
this.setState({exercise_name: e.target.value})
}
exercise_description_change = (e) => {
this.setState({exercise_description: e.target.value})
}
// #问题的类型0为单选题1为多选题2为判断题3为填空题4为主观题5为实训题
_checkIsEditing = () => {
if (this.editingId && $(this.editingId).length ) {
this.props.showNotification('请先保存或取消当前正在编辑的问题。')
$("html").animate({ scrollTop: $(this.editingId).offset().top - 100})
return true
}
return false
}
onEditorCancel = () => {
this.editingId = null;
// 找到编辑或新建的item新建就删掉item编辑就isNew改为false
const { exercise_questions } = this.state
let index = -1;
for(let i = 0; i < exercise_questions.length; i++) {
if (exercise_questions[i].isNew == true) {
index = i;
break;
}
}
if (exercise_questions[index].question_id) { // 编辑
this.setState(
(prevState) => ({
exercise_questions : update(prevState.exercise_questions, {[index]: { isNew: {$set: false}}})
// update(prevState.exercise_questions, {$splice: [[index, 1]]})
})
)
} else { // 新建
this.setState(
(prevState) => ({
exercise_questions : update(prevState.exercise_questions, {$splice: [[index, 1]]})
})
)
}
}
addQuestion = (question_id_to_insert_after, type) => {
if (!this.isEdit) {
this.props.showNotification('请先输入试卷标题,并保存试卷')
return;
}
if (this._checkIsEditing()) {
return;
}
if (type == Q_TYPE_SHIXUN) {
this.addShixun(question_id_to_insert_after)
} else {
this.addEditingQuestion(type, question_id_to_insert_after)
}
}
chooseShixun = (array) => {
this.addEditingQuestion(Q_TYPE_SHIXUN, this.question_id_to_insert_after, {
shixun_id: array[0]
})
}
chooseShixunSuccess = () => {
this.refs.shixunChooseModal.setVisible(false)
}
addShixun = (question_id_to_insert_after) => {
if (!this.isEdit) {
this.props.showNotification('请先输入试卷标题,并保存试卷')
return;
}
// TODO 弹框选择实训
if (this._checkIsEditing()) {
return;
}
this.refs.shixunChooseModal.setVisible(true)
this.question_id_to_insert_after = question_id_to_insert_after;
return;
// 拉取实训items
this.addEditingQuestion(Q_TYPE_SHIXUN, question_id_to_insert_after, {
shixun_id: 50
})
}
editQestion = (index) => {
if (this._checkIsEditing()) {
return;
}
this.editingId = `#question_${index}`
this.setState(
(prevState) => ({
exercise_questions : update(prevState.exercise_questions, {[index]: { isNew: {$set: true}}})
})
)
}
onSort = (index, question_id, isUp) => {
if (this._checkIsEditing()) {
return;
}
const url = `/exercise_questions/${question_id}/up_down.json`
axios.post(url, { opr: isUp ? 'up' : 'down'})
.then((response) => {
if (response.data.status == 0) {
// this.props.showNotification('移动成功')
this.fetchExercise()
}
})
.catch(function (error) {
console.log(error);
});
}
onSortDown = (index, question_id) => {
this.onSort(index, question_id, false)
}
onSortUp = (index, question_id) => {
this.onSort(index, question_id, true)
}
getInitScore = (question_type, question_id_to_insert_after) => {
/**
1.每个题型的首个题目默认值规则如下
选择题5 01
判断题2 2
填空题2 3
简答题10 4
实训题每个关卡5分 5
*/
let init_question_score = 0;
if (question_type == 0 || question_type == 1) {
init_question_score = 5
} else if (question_type == 2) {
init_question_score = 2
} else if (question_type == 3) {
init_question_score = 2
} else if (question_type == 4) {
init_question_score = 10
} else if (question_type == 5) {
init_question_score = 5
}
const _indexBefore = question_id_to_insert_after ? this.findIndexById(question_id_to_insert_after) : this.state.exercise_questions.length - 1
for (let i = _indexBefore; i >= 0; i--) {
if(this.state.exercise_questions[i].question_type == question_type) {
init_question_score = this.state.exercise_questions[i].question_score
break;
}
}
return init_question_score;
}
addEditingQuestion = (question_type, question_id_to_insert_after, otherAttributes) => {
let init_question_score = this.getInitScore(question_type, question_id_to_insert_after)
let questionObj = {
question_type: question_type, // 需要这个通过类型判断
init_question_score: init_question_score,
isNew: true, // 新建或编辑用是否有id区分是新建还是编辑
question_id_to_insert_after,
...otherAttributes
}
const { exercise_questions } = this.state;
let new_exercise_questions = exercise_questions.slice(0)
let newIndex = new_exercise_questions.length;
if (question_id_to_insert_after) {
const _indexBefore = this.findIndexById(question_id_to_insert_after)
new_exercise_questions.splice(_indexBefore + 1, 0, questionObj)
newIndex = _indexBefore + 1
} else {
new_exercise_questions.push(questionObj)
}
this.editingId = `#question_${newIndex}`
this.setState({ exercise_questions: new_exercise_questions }, () => {
setTimeout(() => {
$(this.editingId).length && $("html").animate({ scrollTop: $(this.editingId).offset().top - 100})
}, 500)
})
}
findIndexById = (id) => {
const { exercise_questions } = this.state
for(let i = 0; i < exercise_questions.length; i++) {
if (exercise_questions[i].question_id == id) {
return i;
}
}
}
onQestionDelete = (question_id) => {
this.props.confirm({
content: `确认要删除这个问题吗?`,
onOk: () => {
const url = `/exercise_questions/${question_id}.json`
axios.delete(url)
.then((response) => {
if (response.data.status == 0) {
this.props.showNotification('删除成功')
this.fetchExercise()
// const { exercise_questions } = this.state
// const index = this.findIndexById(question_id)
// this.setState(
// (prevState) => ({
// exercise_questions : update(prevState.exercise_questions, {$splice: [[index, 1]]})
// })
// )
}
})
.catch(function (error) {
console.log(error);
});
}
})
}
addSuccess = () => {
this.editingId = null;
this.fetchExercise()
}
goToPreview = () => {
const exercise_id = this.props.match.params.Id
const courseId = this.props.match.params.coursesId
this.props.history.push(`/courses/${courseId}/exercises/${exercise_id}/student_exercise_list?tab=2`)
}
getAddQuestionUrl = () => {
const Id = this.props.match.params.Id
const url = this.props.exercise_url_questions ? `/${this.props.exercise_url_questions}.json` : `/exercises/${Id}/exercise_questions.json`
return url;
}
getEditQuestionUrl = (question_id) => {
const editUrl = this.props.exercise_url_questions ? `/${this.props.exercise_url_questions}/${question_id}.json` : `/exercise_questions/${question_id}.json`
return editUrl;
}
render() {
let { exercise_name, exercise_description, course_id, exercise_types,
exercise_questions, left_banner_id } = this.state;
// if (this.isEdit && !exercise_types) {
// return ''
// }
// const { getFieldDecorator } = this.props.form;
const { q_counts, q_scores, q_doubles, q_doubles_scores, q_judges, q_judges_scores,
q_mains, q_mains_scores, q_nulls, q_nulls_scores, q_shixuns, q_shixuns_scores, q_singles, q_singles_scores} = exercise_types;
const formItemLayout = {
labelCol: {
xs: { span: 24 },
// sm: { span: 8 },
sm: { span: 24 },
},
wrapperCol: {
xs: { span: 24 },
// sm: { span: 16 },
sm: { span: 24 },
},
};
const { current_user } = this.props
const isAdmin = this.props.isAdmin()
const courseId=this.props.match.params.coursesId;
const exercise_id = this.props.match.params.Id
const isEdit = this.isEdit
const commonHandler = {
onQestionDelete: this.onQestionDelete,
addSuccess: this.addSuccess,
addQuestion: this.addQuestion,
onEditorCancel: this.onEditorCancel,
changeScore:this.changeScore,
editQestion: this.editQestion,
onSortDown: this.onSortDown,
onSortUp: this.onSortUp,
displayCount: exercise_questions.length,
exercise_status: this.state.exercise_status,
exerciseIsPublish: this.state.exercise_status >= 2,
getAddQuestionUrl: this.getAddQuestionUrl,
getEditQuestionUrl: this.getEditQuestionUrl,
}
return(
<React.Fragment>
<ShixunChooseModal
ref="shixunChooseModal"
chooseShixun={this.chooseShixun}
{...this.props}
singleChoose={true}
shixunsUrl={this.props.shixunsUrl}
></ShixunChooseModal>
<style>{`
.courseForm .formBlock {
padding: 20px 30px 30px 30px;
border-bottom: 1px solid #EDEDED;
margin-bottom: 0px;
background: #fff;
}
.exerciseNew .markdown-body {
max-width: 1128px;
}
`}</style>
{!this.state.editMode && <div className="padding20-30" style={{ background: '#fff'}}>
<div className="displayTitle font-16">
<span>{exercise_name}</span>
<a className="fr mr6" onClick={() => { this.setState({editMode: true}) }} style={{ lineHeight: '32px'}}>
<Tooltip title="编辑"><i className="iconfont icon-bianjidaibeijing font-20 color-green"></i></Tooltip>
</a>
</div>
<div className="displayDescription color-grey-9" dangerouslySetInnerHTML={{__html: exercise_description}}
style={{whiteSpace: 'pre-wrap'}}
></div>
</div>}
{this.state.editMode && <Form {...formItemLayout} onSubmit={this.handleSubmit}>
<div className="formBlock" style={{paddingBottom: '2px',borderBottom:"none"}}>
<Form.Item
label="试卷标题"
required
className="topicTitle "
>
{/* {getFieldDecorator('subject', {
rules: [{
required: true, message: '请输入标题',
}, {
max: 20, message: '最大限制为20个字符',
}],
})( */}
<style>
{
`
.exercicenewinputysl .ant-input{
border-right: none !important;
height: 40px !important;
}
`
}
</style>
<Input placeholder={`请输入试卷标题,最大限制${TITLE_MAX_LENGTH}个字符`} maxLength={TITLE_MAX_LENGTH} className="mt5 exercicenewinputysl" value={exercise_name}
onChange={this.exercise_name_change} addonAfter={`${exercise_name ? exercise_name.length : 0}/${TITLE_MAX_LENGTH}`}
/>
{/* )} */}
</Form.Item>
<Form.Item
label="&nbsp;&nbsp;试卷须知"
>
{/* {getFieldDecorator('select_board_id', {
// initialValue: '3779',
})( */}
<TextArea placeholder="请在此输入本次试卷答题的相关说明最大限制100个字符" className="mt5" style={{height:"120px"}} value={exercise_description}
onChange={this.exercise_description_change}
/>
{/* )} */}
</Form.Item>
<Form.Item>
{/* defalutSubmitbtn */}
<a className="task-btn task-btn-orange fr mt4" style={{height: '30px', width: '70px'}}
onClick={this.onSaveExercise}
>保存</a>
{ this.isEdit && <a onClick={() => this.setState({editMode: false})} className="defalutCancelbtn fr mt4"
style={{height: '30px', width: '70px', fontSize: '14px', lineHeight: '30px', marginRight: '16px'}}>取消</a>}
{/* <Button type="primary" onClick={this.onSaveExercise} className="fr">保存</Button> */}
</Form.Item>
</div>
{/* <div className="clearfix mt30 mb30">
<a className="defalutCancelbtn fl" onClick={() => {}}>取消</ a>
</div> */}
</Form>}
<p className="clearfix padding20-30 color-grey-9">
<span className="fl">
{ !!q_singles && <span className="mr20">单选题{q_singles}{q_singles_scores}</span>}
{ !!q_doubles && <span className="mr20">多选题{q_doubles}{q_doubles_scores}</span>}
{ !!q_judges && <span className="mr20">判断题{q_judges}{q_judges_scores}</span>}
{ !!q_nulls && <span className="mr20">填空题{q_nulls}{q_nulls_scores}</span>}
{ !!q_mains && <span className="mr20">简答题{q_mains}{q_mains_scores}</span>}
{ !!q_shixuns && <span className="mr20">实训题{q_shixuns}{q_shixuns_scores}</span> }
</span>
<span className="fr">
{ !!q_counts &&
<span>
合计 <span className="color-blue">{q_counts}</span>
<span className={`${q_scores > 100 ? 'color-red font-bd' : 'color-orange'}`}>{q_scores}</span>
</span>
}
</span>
</p>
<div className="edu-back-white">
{ exercise_questions.map((item, index) => {
if (item.question_type == 0 || item.question_type == 1) {
if (item.isNew) {
return <SingleEditor {...this.props} {...item} index={index} {...commonHandler}></SingleEditor>
} else {
return <SingleDisplay {...this.props} {...item} index={index} {...commonHandler}
displayCount={exercise_questions.length}
></SingleDisplay>
}
} else if (item.question_type == 2) {
if (item.isNew) {
return <JudgeEditor {...this.props} {...item} index={index} {...commonHandler}></JudgeEditor>
} else {
return <JudgeDisplay {...this.props} {...item} index={index} {...commonHandler} ></JudgeDisplay>
}
} else if (item.question_type == 3) {
if (item.isNew) {
return <NullEditor {...this.props} {...item} index={index} {...commonHandler}></NullEditor>
} else {
return <NullDisplay {...this.props} {...item} index={index} {...commonHandler} ></NullDisplay>
}
} else if (item.question_type == 4) {
if (item.isNew) {
return <MainEditor {...this.props} {...item} index={index} {...commonHandler} ></MainEditor>
} else {
return <MainDisplay {...this.props} {...item} index={index} {...commonHandler} ></MainDisplay>
}
} else if (item.question_type == 5) {
if (item.isNew) {
return <ShixunEditor {...this.props} {...item} index={index} {...commonHandler}
chooseShixunSuccess={this.chooseShixunSuccess}
></ShixunEditor>
} else {
return <ShixunDisplay {...this.props} {...item} index={index} {...commonHandler} ></ShixunDisplay>
}
}
return <div></div>
})}
{!commonHandler.exerciseIsPublish && <div className="problemShow padding30">
<ActionBtn style="green" className="mr20" onClick={() => this.addQuestion(null, Q_TYPE_SINGLE)}>
<i className="iconfont icon-tianjiafangda color-white font-14 mr5" style={{ marginTop: '-1px', display: 'inline-block'}}></i>
</ActionBtn>
<ActionBtn style="green" className="mr20" onClick={() => this.addQuestion(null, Q_TYPE_JUDGE)}>
<i className="iconfont icon-tianjiafangda color-white font-14 mr5" style={{ marginTop: '-1px', display: 'inline-block'}}></i>
</ActionBtn>
<ActionBtn style="green" className="mr20" onClick={() => this.addQuestion(null, Q_TYPE_NULL)}>
<i className="iconfont icon-tianjiafangda color-white font-14 mr5" style={{ marginTop: '-1px', display: 'inline-block'}}></i>
</ActionBtn>
<ActionBtn style="green" className="mr20" onClick={() => this.addQuestion(null, Q_TYPE_MAIN)}>
<i className="iconfont icon-tianjiafangda color-white font-14 mr5" style={{ marginTop: '-1px', display: 'inline-block'}}></i>
</ActionBtn>
<ActionBtn style="green" className="mr20" onClick={() => this.addShixun(null)}>
<i className="iconfont icon-tianjiafangda color-white font-14 mr5" style={{ marginTop: '-1px', display: 'inline-block'}}></i>
</ActionBtn>
{exercise_id && <ActionBtn style="blue" className="fr" onClick={() => this.goToPreview()}>
{/* <i className="iconfont icon-tianjiafangda color-white font-14 mr5" style={{ marginTop: '-1px', display: 'inline-block'}}></i> */}
试卷预览
</ActionBtn>}
</div>}
</div>
</React.Fragment>
)
}
}
// RouteHOC()
export default (ExerciseNewCommon);

@ -85,7 +85,7 @@ class SingleEditor extends Component{
}*/
const Id = this.props.match.params.Id
if (question_id) {
const editUrl = `/exercise_questions/${question_id}.json`
const editUrl = this.props.getEditQuestionUrl(question_id);
axios.put(editUrl, {
question_title,
question_type: 2,
@ -105,9 +105,10 @@ class SingleEditor extends Component{
console.log(error);
});
} else {
const url = `/exercises/${Id}/exercise_questions.json`
const url = this.props.getAddQuestionUrl();
axios.post(url, {
exercise_bank_id: Id,
question_title,
question_type: 2,
question_score,

@ -70,7 +70,7 @@ class MainEditor extends Component{
}*/
const Id = this.props.match.params.Id
if (question_id) {
const editUrl = `/exercise_questions/${question_id}.json`
const editUrl = this.props.getEditQuestionUrl(question_id);
axios.put(editUrl, {
question_title,
question_type: 4,
@ -88,9 +88,10 @@ class MainEditor extends Component{
console.log(error);
});
} else {
const url = `/exercises/${Id}/exercise_questions.json`
const url = this.props.getAddQuestionUrl();
axios.post(url, {
exercise_bank_id: Id,
question_title,
question_type: 4,
question_score,

@ -124,7 +124,7 @@ class NullEditor extends Component{
}*/
const Id = this.props.match.params.Id
if (question_id) {
const editUrl = `/exercise_questions/${question_id}.json`
const editUrl = this.props.getEditQuestionUrl(question_id);
axios.put(editUrl, {
question_title,
question_type: 3,
@ -145,9 +145,10 @@ class NullEditor extends Component{
console.log(error);
});
} else {
const url = `/exercises/${Id}/exercise_questions.json`
const url = this.props.getAddQuestionUrl();
axios.post(url, {
exercise_bank_id: Id,
question_title,
question_type: 3,
question_score,

@ -113,7 +113,7 @@ class ShixunEditor extends Component{
}*/
const Id = this.props.match.params.Id
if (question_id) {
const editUrl = `/exercise_questions/${question_id}.json`
const editUrl = this.props.getEditQuestionUrl(question_id);
axios.put(editUrl, {
question_title,
question_type: 5,
@ -131,9 +131,10 @@ class ShixunEditor extends Component{
console.log(error);
});
} else {
const url = `/exercises/${Id}/exercise_questions.json`
const url = this.props.getAddQuestionUrl();
axios.post(url, {
exercise_bank_id: Id,
question_title,
question_type: 5,
question_scores,

@ -123,7 +123,7 @@ class SingleEditor extends Component{
}*/
const Id = this.props.match.params.Id
if (question_id) {
const editUrl = `/exercise_questions/${question_id}.json`
const editUrl = this.props.getEditQuestionUrl(question_id);
axios.put(editUrl, {
question_title,
question_type: answerArray.length > 1 ? 1 : 0,
@ -143,9 +143,10 @@ class SingleEditor extends Component{
console.log(error);
});
} else {
const url = `/exercises/${Id}/exercise_questions.json`
const url = this.props.getAddQuestionUrl();
axios.post(url, {
exercise_bank_id: Id,
question_title,
question_type: answerArray.length > 1 ? 1 : 0,
question_score,

@ -35,6 +35,7 @@ class DetailTop extends Component{
getdatalist=()=>{
let courseslist=[];
let keys=1;
let listtype=false;
if(this.props.courses!=undefined&&this.props.courses.length!=0){
if(this.props.detailInfoList.has_start===true){
this.props.courses.map((item,key)=>{
@ -47,14 +48,31 @@ class DetailTop extends Component{
})
}else{
this.props.courses.map((item,key)=>{
if(this.props.pathtopskey===key+1){
keys=key+1
return(
courseslist.push(item)
)
}
})
this.props.courses.map((item,key)=>{
if(listtype===false){
keys=key+1
if(item.course_status.status===0) {
listtype=true
return (
courseslist.push(item)
)
}
}
})
this.props.courses.map((item,key)=>{
if(listtype===false){
keys=key+1
if(item.course_status.status===2) {
listtype=true
return (
courseslist.push(item)
)
}
}
})
}
}
this.setState({

@ -782,14 +782,14 @@ submittojoinclass=(value)=>{
<style>
{
`
.posi-searchs{
opacity: 1;
position: absolute;
top: -2px;
background: #fff;
z-index:10000;
right: 185px;
}
.posi-searchs{
opacity: 1;
position: absolute;
top: -2px;
background: #fff;
z-index:10000;
right: 185px;
}
`
}
</style>
@ -869,6 +869,11 @@ submittojoinclass=(value)=>{
<li style={{display: this.props.Headertop === undefined ? 'none' : this.props.Headertop.customer_management_url===null || this.props.Headertop.customer_management_url===""? 'none' : 'block'}}>
<a href={this.props.Headertop === undefined ? '' : this.props.Headertop.customer_management_url}>客户管理</a>
</li>
{
this.props.Headertop && this.props.Headertop.college_identifier &&
<li><a href={`/colleges/${this.props.Headertop.college_identifier}/statistics`}>学院统计</a></li>
}
<li><a href={`/account/profile`}>账号管理</a></li>
{/*<li><a onClick={()=>this.educoderlogin()} >登入测试接口</a></li>*/}
{/*<li><a onClick={()=>this.trialapplications()} >试用申请</a> </li>*/}

@ -32,6 +32,10 @@ const HomeworkBanksEdit = Loadable({
loader: () => import('./HomeworkBanksEdit'),
loading: Loading,
});
const ExerciseBanksEdit = Loadable({
loader: () => import('./ExerciseBanksEdit'),
loading: Loading,
});
//普通作业题库详情
const Generaljobbankdetails =Loadable({
@ -134,6 +138,14 @@ class BanksIndex extends Component{
}
}></Route>
<Route path='/banks/exercise/:Id/edit'
render={
(props) => {
return (<ExerciseBanksEdit {...this.props} {...props} {...this.state} {...common}
/>)
}
}></Route>
<Route path='/banks/gtopic/:bankId/edit'
render={
(props) => {

@ -0,0 +1,66 @@
import React, { Component } from 'react';
import axios from 'axios'
import ExerciseNewCommon from '../../../courses/exercise/ExerciseNewCommon'
class ExerciseBanksEdit extends Component {
constructor(props){
super(props);
this.state = {
isPublic: undefined,
// isGroup: false
}
}
componentDidMount = () =>{
}
initData = (responseData) =>{
const Id = this.props.match.params.Id
const crumbData={
title:'编辑',
is_public: responseData && responseData.data && responseData.data.exercise.is_public,
crumbArray:[
{to:`/banks/exercise/${Id}`,content:'详情'},
{content:'编辑'}
]
}
this.props.initPublic(crumbData);
}
render(){
let { workId } = this.props.match.params
const common = {
// onCancel:this.onCancel,
// isGroup: this.isGroup,
// doNew: this.doNew,
// doEdit: this.doEdit,
initData: this.initData
}
return(
<div className="courseForm">
<style>
{`
.courseForm .ant-col-sm-24{
text-align:left;
}
`}
</style>
<ExerciseNewCommon
{...this.props}
{...this.state}
{...common}
wrappedComponentRef={(ref) => this.exerciseNewCommonRef = ref}
isEdit={true}
shixunsUrl={`/exercise_banks/choose_shixun.json`}
exercise_url={'exercise_banks'}
exercise_url_questions={'exercise_bank_questions'}
></ExerciseNewCommon>
</div>
)
}
}
export default ExerciseBanksEdit;

@ -26,7 +26,7 @@ class HomeworkBanksEdit extends Component {
title:'编辑',
is_public:result && result.data && result.data.is_public,
crumbArray:[
{to:`/banks/${this.getModuleName()}/${workId}/edit`,content:'详情'},
{to:`/banks/${this.getModuleName()}/${workId}`,content:'详情'},
{content:'编辑'}
]
}

Loading…
Cancel
Save