From 87e0aa098b7b12777d662080ee32d7fafcaba7e6 Mon Sep 17 00:00:00 2001 From: cxt <853663049@qq.com> Date: Thu, 19 Dec 2019 09:34:34 +0800 Subject: [PATCH 01/39] =?UTF-8?q?=E5=A4=B4=E9=83=A8=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=E5=8A=A0=E4=B8=8A=E5=AD=A6=E6=A0=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/colleges_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/colleges_controller.rb b/app/controllers/colleges_controller.rb index 71009d2dd..51a8b7123 100644 --- a/app/controllers/colleges_controller.rb +++ b/app/controllers/colleges_controller.rb @@ -21,7 +21,7 @@ class CollegesController < ApplicationController # 实训总数 @shixuns_count = Shixun.visible.joins('left join user_extensions on user_extensions.user_id = shixuns.user_id') .where(user_extensions: { school_id: current_school.id }).count - render json: { teachers_count: @teachers_count, students_count: @students_count, courses_count: @courses_count, shixuns_count: @shixuns_count } + render json: { teachers_count: @teachers_count, students_count: @students_count, courses_count: @courses_count, shixuns_count: @shixuns_count, school: current_school.name } end def shixun_time From 1f58b60a0d80d438bd31cbef4908a20a4d658515 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=9E=97?= <904079904@qq.com> Date: Thu, 19 Dec 2019 14:52:45 +0800 Subject: [PATCH 02/39] =?UTF-8?q?=E6=96=B0=E7=89=88=E5=AD=A6=E9=99=A2?= =?UTF-8?q?=E7=BB=9F=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/react/src/App.js | 12 +- public/react/src/college/College.js | 1222 +++++++++++++++++ .../college/colleagechart/Colleagechart.js | 84 ++ .../college/colleagechart/Colleagechartzu.js | 149 ++ .../src/college/colleagecss/colleage.css | 213 +++ 5 files changed, 1679 insertions(+), 1 deletion(-) create mode 100644 public/react/src/college/College.js create mode 100644 public/react/src/college/colleagechart/Colleagechart.js create mode 100644 public/react/src/college/colleagechart/Colleagechartzu.js create mode 100644 public/react/src/college/colleagecss/colleage.css diff --git a/public/react/src/App.js b/public/react/src/App.js index 4694d57da..ecb45cd1a 100644 --- a/public/react/src/App.js +++ b/public/react/src/App.js @@ -300,6 +300,11 @@ const Developer = Loadable({ loader: () => import('./modules/developer'), loading: Loading }) +// 学院统计 +const College = Loadable({ + loader: () => import('./college/College'), + loading: Loading +}) // 开发者编辑模块 const NewOrEditTask = Loadable({ @@ -614,7 +619,10 @@ class App extends Component { {/*/>*/} <Route path="/shixuns/new" component={Newshixuns}> </Route> - + <Route path="/colleges/:id/statistics" + render={ + (props) => (<College {...this.props} {...props} {...this.state} />) + }/> {/* jupyter */} <Route path="/tasks/:identifier/jupyter/" render={ @@ -692,6 +700,7 @@ class App extends Component { } } /> + <Route path="/problems/:id/edit" render={ @@ -706,6 +715,7 @@ class App extends Component { render={ (props) => (<StudentStudy {...this.props} {...props} {...this.state} />) } /> + <Route path="/problems" render={ (props) => (<Developer {...this.props} {...props} {...this.state} />) diff --git a/public/react/src/college/College.js b/public/react/src/college/College.js new file mode 100644 index 000000000..c503d5387 --- /dev/null +++ b/public/react/src/college/College.js @@ -0,0 +1,1222 @@ +import React, {Component} from "react"; +import {Link, NavLink} from 'react-router-dom'; +import {WordsBtn, ActionBtn,SnackbarHOC,getImageUrl} from 'educoder'; +import axios from 'axios'; +import { + notification, + Spin, + Table, + Pagination, +} 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 './colleagecss/colleage.css'; +import Shixunechart from "../modules/courses/shixunHomework/shixunreport/Shixunechart"; +class College extends Component { + constructor(props) { + super(props); + // this.answerMdRef = React.createRef(); + this.state = { + coursesloading:false, + columns: [ + { + title: '名称', + dataIndex: 'name', + key: 'name', + align: 'center', + className: "edu-txt-center font-14 maxnamewidth247", + render: (text, record) => ( + <a href={`/courses/${record.id}/students`} title={record.name} target="_blank" className="d-inline-block text-truncate maxnamewidth247" + style={{ + maxWidth:'220px', + color:'#007bff', + }}>{ + record.name + }</a> + ) + }, + { + title: '管理教师', + dataIndex: 'teachers', + key: 'teachers', + align: 'center', + className: "edu-txt-center font-14 maxnamewidth340", + render: (text, record) => ( + <span className="maxnamewidth340"> + { + record.teachers + } + </span> + ) + }, + { + title: '评测次数', + dataIndex: 'times', + key: 'times', + align: 'center', + className: "edu-txt-center font-14 maxnamewidth175", + render: (text, record) => ( + <span> + { + record.evaluating_count + } + </span> + ), + }, + { + title: '学生', + key: 'student', + dataIndex: 'student', + align: 'center', + className: "edu-txt-center font-14 maxnamewidth255", + render: (text, record) => ( + <span> + { + record.student_count + } + </span> + ) + }, + { + title: '实训作业', + dataIndex: 'training', + key: 'training', + align: 'center', + className: "edu-txt-center font-14", + render: (text, record) => ( + <span> + { + record.shixun_work_count + } + </span> + ) + + }, + { + title: '资源', + dataIndex: 'resources', + key: 'resources', + align: 'center', + className: "edu-txt-center font-14", + render: (text, record) => ( + <span> + { + record.attachment_count + } + </span> + ), + }, + { + title: '帖子', + dataIndex: 'posts', + key: 'posts', + align: 'center', + className: "edu-txt-center font-14", + render: (text, record) => ( + <span>{ + record.message_count + }</span> + ) + }, + { + title: '其它任务', + dataIndex: 'othertasks', + key: 'othertasks', + align: 'center', + className: "edu-txt-center font-14", + render: (text, record) => ( + <span> + { + record.other_work_count + } + </span> + ) + }, + { + title: '状态', + dataIndex: 'states', + key: 'states', + align: 'center', + className: "edu-txt-center font-14", + render: (text, record) => ( + <span className={record.is_end?'':'color-huang'}> + { + record.is_end? + "已结束" + : + "正在进行" + } + </span> + ) + }, + { + title: '时间', + dataIndex: 'timemy', + key: 'timemy', + align: 'center', + className: "edu-txt-center font-14", + render: (text, record) => ( + <span > + { + record.activity_time + } + </span> + ) + }, + ], + page:1, + limit:10, + total_users:50, + teachersloading:false, + teacherranking:[ + { + title: '排名', + dataIndex: 'ranking', + key: 'ranking', + align: 'center', + className: "edu-txt-center font-14", + render: (text, record) => ( + <span> + { + record.id + } + </span> + ) + }, + { + title: '姓名', + dataIndex: 'name', + key: 'name', + align: 'center', + className: "edu-txt-center font-14 maxnamewidth105", + render: (text, record) => ( + <a href={`/users/${record.login}`} title={record.name} target="_blank" className="task-hide maxnamewidth105" style={{ + color:'#007bff', + + }}> { + record.name + } + </a> + ) + }, + { + title: '管理课堂', + dataIndex: 'classroom', + key: 'classroom', + align: 'center', + className: "edu-txt-center font-14 maxnamewidth175", + render: (text, record) => ( + <span> + { + record.course_count + } + </span> + ), + }, + { + title: '已发布实训作业', + key: 'assignment', + dataIndex: 'assignment', + align: 'center', + className: "edu-txt-center font-14 maxnamewidth255", + render: (text, record) => ( + <span> + { + record.shixun_work_count + } + </span> + ) + }, + { + title: '未发布实训作业', + dataIndex: 'released', + key: 'released', + align: 'center', + className: "edu-txt-center font-14", + render: (text, record) => ( + <span> + { + record.un_shixun_work_count + } + </span> + ) + + }, + { + title: '学生数', + dataIndex: 'studentnumber', + key: 'studentnumber', + align: 'center', + className: "edu-txt-center font-14", + render: (text, record) => ( + <span> + { + record.student_count + } + </span> + ), + }, + { + title: '完成率', + dataIndex: 'completionrate', + key: 'completionrate', + align: 'center', + className: "edu-txt-center font-14", + render: (text, record) => ( + <span> + { + record.complete_rate+"%" + } + </span> + ) + }, + { + title: '发布实训', + dataIndex: 'releasetraining', + key: 'releasetraining', + align: 'center', + className: "edu-txt-center font-14", + render: (text, record) => ( + <span className="color-blue"> + { + record.publish_shixun_count + } + </span> + ) + } + ], + studentranking:[ + { + title: '排名', + dataIndex: 'ranking', + key: 'ranking', + align: 'center', + className: "edu-txt-center font-14", + width:'100px', + render: (text, record) => ( + <span> + { + record.id===1? <img width="18px" height="22px" className="mt8" src={getImageUrl("/images/educoder/competition/1.png")}/> + :record.id===2? + <img width="18px" height="22px" className="mt8" src={getImageUrl("/images/educoder/competition/2.png")}/> + :record.id===3? + <img width="18px" height="22px" className="mt8" src={getImageUrl("/images/educoder/competition/3.png")}/> + :record.id + } + </span> + ) + }, + { + title: '姓名', + dataIndex: 'name', + key: 'name', + align: 'center', + className: "edu-txt-center font-14 maxnamewidth105", + width:'100px', + render: (text, record) => ( + <a href={`/users/${record.login}`} title={record.name} target="_blank" className="task-hide maxnamewidth105" style={{ + color:'#007bff', + + }}> { + record.name + } + </a> + ) + }, + { + title: '学号', + dataIndex: 'studentid', + key: 'studentid', + align: 'center', + className: "edu-txt-center font-14 maxnamewidth175", + render: (text, record) => ( + <span> + { + record.student_id + } + </span> + ), + }, + { + title: '完成实训', + key: 'training', + dataIndex: 'training', + align: 'center', + className: "edu-txt-center font-14 maxnamewidth255", + render: (text, record) => ( + <span> + { + record.shixun_count + } + </span> + ) + }, + { + title: '在学实训', + dataIndex: 'learning', + key: 'learning', + align: 'center', + className: "edu-txt-center font-14", + render: (text, record) => ( + <span> + { + record.study_shixun_count + } + </span> + ) + + }, + { + title: '金币', + dataIndex: 'goldcoin', + key: 'goldcoin', + align: 'center', + className: "edu-txt-center font-14", + render: (text, record) => ( + <span> + { + record.grade + } + </span> + ), + }, + { + title: '经验值', + dataIndex: 'empirical', + key: 'empirical', + align: 'center', + className: "edu-txt-center font-14", + render: (text, record) => ( + <span style={{ + color:'#17a2b8' + }}> + { + record.experience + } + </span> + ) + }, + ], + school:"", + teachers_count:null, + students_count:null, + courses_count:null, + shixuns_count:null, + shixun_report_count:null, + shixun_time:null, + courses:null, + course_count:0, + pages:1, + limits:10, + teachers:null, + teacher_count:0, + students:null, + student_count:0, + shixun_chart_data:null, + shixun_chart_datanames:null + } + + } + + + componentDidMount(){ + console.log("College"); + console.log(this.props.match.params.id); + this.gettop(); + this.Numberofinternshipreports(); + this.Actualcombattimeoftrainees(); + this.Classnumber(1,10); + this.Teacherranking(1,10); + this.Studentranking(1,10); + this.Onlinetraining(); + this.Hottest(); + } + //头部 + gettop=()=>{ + const id =this.props.match.params.id; + const url=`/colleges/${id}/statistics.json`; + axios.get(url).then((response) => { + if(response===null||response===undefined){ + this.setState({ + teachers_count:0, + students_count:0, + courses_count:0, + shixuns_count:0, + school:"", + }) + return + } + if (response.data.status === 403||response.data.status === 401||response.data.status === 500) { + this.setState({ + teachers_count:0, + students_count:0, + courses_count:0, + shixuns_count:0, + school:"", + }) + }else{ + this.setState({ + teachers_count:response.data.teachers_count, + students_count:response.data.students_count, + courses_count:response.data.courses_count, + shixuns_count:response.data.shixuns_count, + school:response.data.school, + }) + } + }).catch((error) => { + console.log(error) + this.setState({ + teachers_count:0, + students_count:0, + courses_count:0, + shixuns_count:0, + school:"", + }) + }); + } + + //获取实训报告数 + Numberofinternshipreports=()=>{ + const id =this.props.match.params.id; + const url=`/colleges/${id}/shixun_report_count.json`; + axios.get(url).then((response) => { + if(response===null||response===undefined){ + this.setState({ + shixun_report_count:0, + }) + return + } + if (response.data.status === 403||response.data.status === 401||response.data.status === 500) { + this.setState({ + shixun_report_count:0, + }) + }else{ + if (response.data.status === -1){ + this.setState({ + shixun_report_count:0, + }) + return + } + this.setState({ + shixun_report_count:response.data.shixun_report_count, + }) + } + }).catch((error) => { + console.log(error) + this.setState({ + shixun_report_count:0, + }) + }); + } + + //学员实战时间 + Actualcombattimeoftrainees=()=>{ + const id =this.props.match.params.id; + const url=`/colleges/${id}/shixun_time.json`; + axios.get(url).then((response) => { + if(response===null||response===undefined){ + this.setState({ + shixun_time:0, + }) + return + } + if (response.data.status === 403||response.data.status === 401||response.data.status === 500) { + this.setState({ + shixun_time:0, + }) + }else{ + if (response.data.status === -1){ + this.setState({ + shixun_time:0, + }) + return + } + this.setState({ + shixun_time:response.data.shixun_time, + }) + } + }).catch((error) => { + console.log(error) + this.setState({ + shixun_time:0, + }) + }); + } + + //课堂信息 + Classnumber=(page,per_page)=>{ + const id =this.props.match.params.id; + const url=`/colleges/${id}/course_statistics.json`; + this.setState({ + coursesloading:true + }) + axios.get(url,{params:{ + page:page, + per_page:per_page, + } + }).then((response) => { + if(response===null||response===undefined){ + this.setState({ + courses:[], + course_count:0 + }) + return + } + if (response.data.status === 403||response.data.status === 401||response.data.status === 500) { + this.setState({ + courses:[], + course_count:0 + }) + }else{ + if (response.data.status === -1){ + this.setState({ + courses:[], + course_count:0 + }) + return + } + this.setState({ + courses:response.data.courses, + course_count:response.data.course_count, + page:page, + limit:per_page + }) + } + this.setState({ + coursesloading:false + }) + }).catch((error) => { + this.setState({ + courses:[], + course_count:0, + coursesloading:false + }) + }); + } + + //教师排名 + Teacherranking=(page,per_page)=>{ + const id =this.props.match.params.id; + const url=`/colleges/${id}/teachers.json`; + this.setState({ + teachersloading:true + }) + axios.get(url,{params:{ + page:page, + per_page:per_page, + } + }).then((response) => { + if(response===null||response===undefined){ + this.setState({ + teachers:[], + teacher_count:0 + }) + return + } + if (response.data.status === 403||response.data.status === 401||response.data.status === 500) { + this.setState({ + teachers:[], + teacher_count:0 + }) + }else{ + if (response.data.status === -1){ + this.setState({ + teachers:[], + teacher_count:0 + }) + return + } + let teachers=[]; + if(response.data.teachers){ + for(let i=0;i<response.data.teachers.length;i++){ + let datay={ + id:(i+(page-1)*10)+1, + login: response.data.teachers[i].login, + name: response.data.teachers[i].name, // 姓名 + course_count: response.data.teachers[i].course_count, // 课堂数 + shixun_work_count:response.data.teachers[i].shixun_work_count, // 已发布实训作业 + un_shixun_work_count:response.data.teachers[i].un_shixun_work_count, // 未发布实训作业 + student_count: response.data.teachers[i].student_count, // 学生数 + complete_rate: response.data.teachers[i].complete_rate, // 完成率 + publish_shixun_count: response.data.teachers[i].publish_shixun_count, // 发布实训数 + } + teachers.push(datay); + + } + + } + this.setState({ + teachers:teachers, + teacher_count:response.data.teacher_count, + pages:page, + limits:per_page, + }) + } + this.setState({ + teachersloading:false + }) + }).catch((error) => { + this.setState({ + teachers:[], + teacher_count:0, + teachersloading:false + }) + }); + } + //学生排名 + + Studentranking=(page,per_page)=>{ + const id =this.props.match.params.id; + const url=`/colleges/${id}/student_shixun.json`; + this.setState({ + studentsloading:true + }) + axios.get(url,{params:{ + page:page, + per_page:per_page, + } + }).then((response) => { + if(response===null||response===undefined){ + this.setState({ + students:[], + student_count:0, + }) + return + } + if (response.data.status === 403||response.data.status === 401||response.data.status === 500) { + this.setState({ + students:[], + student_count:0, + }) + }else{ + if (response.data.status === -1){ + this.setState({ + students:[], + student_count:0, + }) + return + } + let students=[]; + if(response.data.teachers){ + for(let i=0;i<response.data.teachers.length;i++){ + let datay={ + id:(i+(page-1)*10)+1, + login: response.data.teachers[i].login, + name: response.data.teachers[i].name, // 姓名 + student_id: response.data.teachers[i].student_id, + shixun_count:response.data.teachers[i].shixun_count, + study_shixun_count:response.data.teachers[i].study_shixun_count, + grade: response.data.teachers[i].grade, + experience: response.data.teachers[i].experience, + } + students.push(datay); + } + } + this.setState({ + students:students, + student_count:response.data.student_count, + pagess:page, + limitss:per_page, + }) + } + this.setState({ + studentsloading:false + }) + }).catch((error) => { + this.setState({ + students:[], + student_count:0, + studentsloading:false + }) + }); + } + + //在线实训情况 + Onlinetraining=()=>{ + const id =this.props.match.params.id; + const url=`/colleges/${id}/shixun_chart_data.json`; + axios.get(url).then((response) => { + this.setState({ + shixun_chart_data:response.data.data, + shixun_chart_datanames:response.data.names + }) + }).catch((error) => { + + }); + } + //最热测评 + Hottest=()=>{ + const id =this.props.match.params.id; + const url=`/colleges/${id}/student_hot_evaluations.json`; + axios.get(url).then((response) => { + this.setState({ + studentionsnames:response.data.names, + studentionsvalues:response.data.values + }) + }).catch((error) => { + + }); + } + + table1handleChange(){ + + } + + //塞选 + paginationonChange=(pageNumber)=>{ + this.Classnumber(pageNumber,10); + } + + paginationonChanges=(pageNumber)=>{ + this.Teacherranking(pageNumber,10); + } + paginationonChangess=(pageNumber)=>{ + this.Studentranking(pageNumber,10); + } + render() { + let {columns,page,limit,total_users,teacherranking,studentranking, + teachers_count,students_count, courses_count, shixuns_count,shixun_report_count,shixun_time,courses,course_count,school,teachers, + pages,limits, teacher_count,teachersloading,coursesloading,pagess,limitss,studentsloading,students,student_count,shixun_chart_data, + shixun_chart_datanames, studentionsnames,studentionsvalues + } = this.state; + + return ( + <div className="newMain clearfix edu-back-eeee"> + <div className="yslstatistic-header intermediatecenter" > + <div className="intermediatecenter " style={{ + maxWidth:"1200px", + width:"1200px", + height: '100%', + }}> + <div className="yslstatistic-header-title">{school}</div> + <div className="yslstatistic-header-content"> + <div className="yslstatistic-header-item"> + {/*//教师1*/} + <div className="yslstatistic-header-item-label"> + 教师 + </div> + <div className="yslstatistic-header-item-content"> + {teachers_count?teachers_count:0} + </div> + </div> + + <div className="yslstatistic-header-item"> + <div className="yslstatistic-header-item-label"> + 学生 + </div> + <div className="yslstatistic-header-item-content"> + {students_count?students_count:0} + </div> + </div> + + <div className="yslstatistic-header-item"> + <div className="yslstatistic-header-item-label"> + 课堂 + </div> + <div className="yslstatistic-header-item-content"> + {courses_count?courses_count:0} + </div> + </div> + + <div className="yslstatistic-header-item"> + <div className="yslstatistic-header-item-label"> + 共建实训 + </div> + <div className="yslstatistic-header-item-content"> + {shixuns_count?shixuns_count:0} + </div> + </div> + {/*//教师2*/} + + + + + </div> + </div> + </div> + <div className={"educontent edu-back-white"} style={{width: "1200px"}}> + <p className="h4 linjibenshiyong"> + 基本使用情况 + </p> + {/*基本使用情况1*/} + <div className="jibenshiyong100 sortinxdirection yinyin"> + <p className="yslstatistic-base-item-label"> + 教师 + </p> + <p className="yslstatistic-base-item-label"> + 学生 + </p> + <p className="yslstatistic-base-item-label"> + 课堂 + </p> + <p className="yslstatistic-base-item-label"> + 共建实训 + </p> + <p className="yslstatistic-base-item-label"> + 实习报告 + </p> + <p className="yslstatistic-base-item-label"> + 学员实战时间 + </p> + </div> + + + {/*基本使用情况2*/} + <div className="jibenshiyong100 sortinxdirection yinyin"> + <div className="yslstatistic-base-item-labels"> + { + teachers_count? + <div className="yslstatistic-base-item-labelsp"> {teachers_count}<span className="yslstatistic-base-item-labelsspan">人</span></div> + : + <Spin/> + } + </div> + <div className="yslstatistic-base-item-labels"> + { + students_count? + <div className="yslstatistic-base-item-labelsp">{students_count}<span className="yslstatistic-base-item-labelsspan">人</span></div> + : + <Spin/> + } + </div> + <div className="yslstatistic-base-item-labels"> + { + courses_count? + <div className="yslstatistic-base-item-labelsp">{courses_count}<span className="yslstatistic-base-item-labelsspan">个</span></div> + : + <Spin/> + } + </div> + <div className="yslstatistic-base-item-labels"> + { + shixuns_count? + <div className="yslstatistic-base-item-labelsp">{shixuns_count}<span className="yslstatistic-base-item-labelsspan">个</span></div> + : + <Spin/> + } + </div> + <div className="yslstatistic-base-item-labels"> + { + shixun_report_count? + <div className="yslstatistic-base-item-labelsp">{shixun_report_count}<span className="yslstatistic-base-item-labelsspan">个</span></div> + : + <Spin/> + } + </div> + <div className="yslstatistic-base-item-labels"> + { + shixun_time? + <div className="yslstatistic-base-item-labelsp">{shixun_time}<span className="yslstatistic-base-item-labelsspan">天</span></div> + : + <Spin/> + } + </div> + </div> + {/*基本使用情况3结束*/} + </div> + + + <div className={"educontent edu-back-white mt-4 yinyin"} style={{width: "1200px"}}> + <p className="statistic-label linjibenshiyong"> + 课堂 + </p> + { + courses===null? + <div className="intermediatecenter" style={{ + height:'500px' + }}> + <Spin tip="正在加载..."/> + </div> + + : + JSON.stringify(courses) === "[]" ? + <NoneData> + + </NoneData> + : + <div style={{width: "1200px"}}> + <div className={"justify break_full_word new_li edu-back-white"} + style={{minHeight: "480px"}}> + <style>{` + .ant-spin-nested-loading > div > .ant-spin .ant-spin-dot { + top: 72%;} + } + .ysltableows2 .ant-table-thead > tr > th{ + padding: 9px; + } + + + .ysltableows2 .ant-table-tbody > tr > td { + padding: 15px; + } + + .mysjysltable1 .ant-table-thead > tr > th{ + padding: 9px; + } + + .mysjysltable1 .ant-table-tbody > tr > td { + padding: 15px; + } + .ysltableows2 .ant-table-thead > tr > th{ + background: #F5F5F5; + } + `}</style> + <div className="edu-table edu-back-white ysltableows2"> + {courses === undefined ? "" : <Table + dataSource={courses} + columns={columns} + className="mysjysltable1" + pagination={false} + loading={coursesloading} + // onChange={this.TablePaginationsy} + />} + </div> + </div> + { + course_count>=11? + <div style={{ + width:'100%', + padding:'40px' + }}> + <div className="edu-txt-center "> + <Pagination showQuickJumper current={page} onChange={this.paginationonChange} + pageSize={limit} + total={course_count}></Pagination> + </div> + + </div> + :"" + } + + </div> + } + + + </div> + + + <div className={"educontent edu-back-white yinyin mt-4 sortinxdirection"} style={{width: "1200px"}}> + <div className=" verticallayout" style={{ + width: "65%" + }}> + <p className="statistic-label ysllinjibenshiyong yinyin"> + 教师排名 + </p> + { + teachers===null? + <div className="intermediatecenter" style={{ + height:'500px' + }}> + <Spin tip="正在加载..."/> + </div> + + : + JSON.stringify(teachers) === "[]" ? + <NoneData> + + </NoneData> + : + <div className={"justify break_full_word new_li edu-back-white "} + style={{minHeight: "480px"}}> + <style>{` + .ant-spin-nested-loading > div > .ant-spin .ant-spin-dot { + top: 72%;} + } + .ysltableows2 .ant-table-thead > tr > th{ + padding: 9px; + } + + + .ysltableows2 .ant-table-tbody > tr > td { + padding: 15px; + } + + .mysjysltable1 .ant-table-thead > tr > th{ + padding: 9px; + } + + .mysjysltable1 .ant-table-tbody > tr > td { + padding: 15px; + } + .ysltableows2 .ant-table-thead > tr > th{ + background: #F5F5F5; + } + + `}</style> + <div className="edu-table edu-back-white ysltableows2"> + {teachers === undefined ? "" : <Table + dataSource={teachers} + columns={teacherranking} + className="mysjysltable1" + pagination={false} + loading={teachersloading} + // onChange={this.TablePaginationsy} + />} + </div> + </div> + } + + + + {/*<div style={{*/} + {/* width:'100%',*/} + {/* padding:'40px'*/} + {/*}}>*/} + {/* <div className="edu-txt-center ">*/} + {/* <Pagination showQuickJumper current={pages} onChange={this.paginationonChanges}*/} + {/* pageSize={limits}*/} + {/* total={teacher_count}></Pagination>*/} + {/* </div>*/} + + {/*</div>*/} + </div> + + <div className="" style={{ + width: "35%" + }}><div className="yslslinjibenshiyong" style={{ + height: "100%" + }}> + <p className="statistic-label ysllinjibenshiyong"> + 在线实训情况 + </p> + { + shixun_chart_data===null? + <div className="intermediatecenter" style={{ + height:'500px' + }}> + <Spin tip="正在加载..."/> + </div> + + : + JSON.stringify(shixun_chart_data) === "[]" ? + <NoneData> + + </NoneData> + : + <Colleagechart data={shixun_chart_data} datanane={shixun_chart_datanames}> + + </Colleagechart> + } + + </div> + </div> + </div> + + + <div className={"educontent edu-back-white yinyin mt-4 sortinxdirection mb80"} style={{width: "1200px"}}> + <div className=" verticallayout" style={{ + width: "65%" + }}> + <p className="statistic-label ysllinjibenshiyong yinyin "> + 学生排名 + </p> + { + students === null ? + <div className="intermediatecenter" style={{ + height: '500px' + }}> + <Spin tip="正在加载..."/> + </div> + + : + JSON.stringify(students) === "[]" ? + <NoneData> + + </NoneData> + : + <div className={"justify break_full_word new_li edu-back-white "} + style={{minHeight: "480px"}}> + <style>{` + .ant-spin-nested-loading > div > .ant-spin .ant-spin-dot { + top: 72%;} + } + .ysltableows2 .ant-table-thead > tr > th{ + padding: 9px; + } + + + .ysltableows2 .ant-table-tbody > tr > td { + padding: 15px; + } + + .mysjysltable1 .ant-table-thead > tr > th{ + padding: 9px; + } + + .mysjysltable1 .ant-table-tbody > tr > td { + padding: 15px; + } + .ysltableows2 .ant-table-thead > tr > th{ + background: #F5F5F5; + } + `}</style> + <div className="edu-table edu-back-white ysltableows2"> + {students === undefined ? "" : <Table + dataSource={students} + columns={studentranking} + 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={{ + width: "35%" + }}> + + <div className="yslslinjibenshiyong" style={{ + height: "100%" + }}> + <p className="statistic-label ysllinjibenshiyong"> + 最热评测 + </p> + { + studentionsnames===null? + <div className="intermediatecenter" style={{ + height:'500px' + }}> + <Spin tip="正在加载..."/> + </div> + + : + JSON.stringify(studentionsnames) === "[]" ? + <NoneData> + + </NoneData> + : + <Colleagechartzu data={studentionsnames} datavule={studentionsvalues}> + + </Colleagechartzu> + } + + + </div> + </div> + </div> + </div> + ) + } +} +export default SnackbarHOC() (TPMIndexHOC ( College )); + + diff --git a/public/react/src/college/colleagechart/Colleagechart.js b/public/react/src/college/colleagechart/Colleagechart.js new file mode 100644 index 000000000..1e2767f5a --- /dev/null +++ b/public/react/src/college/colleagechart/Colleagechart.js @@ -0,0 +1,84 @@ +import React, {Component} from "react"; +import {WordsBtn} from 'educoder'; +import {Table} from "antd"; +import {Link,Switch,Route,Redirect} from 'react-router-dom'; +const echarts = require('echarts'); + + + +function startechart(data,datanane){ + var effChart = echarts.init(document.getElementById('shixun_skill_chart')); + + var option = { + + tooltip : { + trigger: 'item', + formatter: "{a} <br/>{b} : {c} ({d}%)" + }, + legend: { + // orient: 'vertical', + // top: 'middle', + bottom: 40, + left: 'center', + data: datanane + }, + series : [ + { + type: 'pie', + radius : '65%', + center: ['50%', '35%'], + selectedMode: 'single', + data:data, + itemStyle: { + emphasis: { + shadowBlur: 10, + shadowOffsetX: 0, + shadowColor: 'rgba(0, 0, 0, 0.5)' + } + } + } + ] + }; + effChart.setOption(option); +} +class Colleagechart extends Component { + + constructor(props) { + super(props); + this.state = { + } + } + + componentDidMount() { + startechart(this.props.data,this.props.datanane) + } + + + componentDidUpdate = (prevProps) => { + if (prevProps.data!= this.props.data) { + startechart(this.props.data,this.props.datanane) + } + } + + + render() { + let {data}=this.props; + + return ( + <div> + + <div + style={{ width:'410px',height:'600px'}} + id="shixun_skill_chart"> + </div> + + + + + </div> + + ) + } +} + +export default Colleagechart; diff --git a/public/react/src/college/colleagechart/Colleagechartzu.js b/public/react/src/college/colleagechart/Colleagechartzu.js new file mode 100644 index 000000000..c65d2f6f2 --- /dev/null +++ b/public/react/src/college/colleagechart/Colleagechartzu.js @@ -0,0 +1,149 @@ +import React, {Component} from "react"; +import {WordsBtn} from 'educoder'; +import {Table} from "antd"; +import {Link,Switch,Route,Redirect} from 'react-router-dom'; +const echarts = require('echarts'); + + + +function startechart(names, values){ + var effChart = echarts.init(document.getElementById('shixun_skill_charts')); + + var Color = ['#962e66', '#623363', '#CCCCCC', '#9A9A9A', '#FF8080', '#FF80C2', '#B980FF', '#80B9FF', '#6FE9FF', '#4DE8B4', '#F8EF63', '#FFB967']; + + var option = { + backgroundColor: '#fff', + grid: { + left: '3%', + right: '4%', + bottom: '10%', + containLabel: true + }, + + 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: 'value', + axisTick: { + show: false + }, + axisLine: { + show: true, + lineStyle: { + color: '#CCCCCC' + } + }, + splitLine: { + show: false, + lineStyle: { + color: '#CCCCCC' + } + }, + axisLabel: { + textStyle: { + color: '#656565', + fontWeight: 'normal', + fontSize: '12' + }, + formatter: '{value}' + } + }, + yAxis: { + type: 'category', + axisLine: { + lineStyle: { + color: '#cccccc' + } + }, + splitLine: { + show: false + }, + axisTick: { + show: false + }, + splitArea: { + show: false + }, + axisLabel: { + inside: false, + textStyle: { + color: '#656565', + fontWeight: 'normal', + fontSize: '12' + } + }, + data: names + }, + series: [{ + name: '', + type: 'bar', + itemStyle: { + normal: { + show: true, + color: function(params) { + return Color[params.dataIndex] + }, + barBorderRadius: 50, + borderWidth: 0, + borderColor: '#333' + } + }, + barGap: '0%', + barCategoryGap: '50%', + data: values + } + + ] + }; + effChart.setOption(option); +} +class Colleagechartzu extends Component { + + constructor(props) { + super(props); + this.state = { + } + } + + componentDidMount() { + startechart(this.props.data,this.props.datavule) + } + + + componentDidUpdate = (prevProps) => { + if (prevProps.data!= this.props.data) { + startechart(this.props.data,this.props.datavule) + } + } + + + render() { + let {data}=this.props; + + return ( + <div> + + <div + style={{ width:'410px',height:'600px'}} + id="shixun_skill_charts"> + </div> + + + + + </div> + + ) + } +} + +export default Colleagechartzu; diff --git a/public/react/src/college/colleagecss/colleage.css b/public/react/src/college/colleagecss/colleage.css new file mode 100644 index 000000000..031396896 --- /dev/null +++ b/public/react/src/college/colleagecss/colleage.css @@ -0,0 +1,213 @@ +.yslstatistic-header { + width: 100%; + height: 240px; + background-image: url('/images/educoder/statistics.jpg'); + background-size: 100% 100%; +} +.yslborder{ + border: 1px solid; +} +.yslstatistic-header-title{ + flex: 1; + display: flex; + align-items: center; + color: #4CACFF; + font-size: 32px; +} +.yslstatistic-header-content{ + width: 100%; + display: flex; + justify-content: space-around; +} +.yslstatistic-header-item{ + margin-bottom: 22px; + display: flex; + flex-direction: column; + align-items: center; + color: #fff; +} +.yslstatistic-header-item-label{ + color: #989898; +} + +.yslstatistic-base-item-label{ + width: 200px; + text-align: center; + font-size: 16px; + height: 48px; + line-height: 48px; + color: #686868; + background: #F5F5F5; + border-top: 1px solid #EBEBEB; +} +.yslstatistic-base-item-labels{ + width: 200px; + text-align: center; + height: 100px; + line-height: 100px; + background: #ffffff; + border-top: 1px solid #EBEBEB; + border-bottom: 1px solid #EBEBEB; +} +.yslstatistic-base-item-labelsp{ + color: #000000; + font-size: 24px; +} +.yslstatistic-base-item-labelsspan{ + color: #000000; + margin-left: 5px; + font-size: 16px; +} +.jibenshiyong100{ + width: 100%; +} + +.yslstatistic-header-item-content{ + font-size: 24px; +} +/* 中间居中 */ +.intermediatecenter{ + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; +} +/* 简单居中 */ +.intermediatecenterysls{ + display: flex; + align-items: center; +} +.spacearound{ + display: flex; + justify-content: space-around; + +} +.spacebetween{ + display: flex; + justify-content: space-between; +} +/* 头顶部居中 */ +.topcenter{ + display: -webkit-flex; + flex-direction: column; + align-items: center; + +} + + +/* x轴正方向排序 */ +/* 一 二 三 四 五 六 七 八 */ +.sortinxdirection{ + display: flex; + flex-direction:row; +} +/* x轴反方向排序 */ +/* 八 七 六 五 四 三 二 一 */ +.xaxisreverseorder{ + display: flex; + flex-direction:row-reverse; +} +/* 垂直布局 正方向*/ +/* 一 + 二 + 三 + 四 + 五 + 六 + 七 + 八 */ +.verticallayout{ + display: flex; + flex-direction:column; +} +/* 垂直布局 反方向*/ +.reversedirection{ + display: flex; + flex-direction:column-reverse; +} + +.h4{ + font-size: 1.5rem; + font-weight: 500 !important; +} +.ysllinjibenshiyong{ + font-weight: 500; + line-height: 1.2; + padding: 2rem 1.25rem; + border-bottom: unset; + background:#fff; +} +.linjibenshiyong{ + font-weight: 500; + line-height: 1.2; + padding: 2rem 1.25rem; + border-bottom: unset; + background:#fff; + box-shadow:0px 6px 12px 0px rgba(0,0,0,0.1); + border-radius:2px; +} +.yslslinjibenshiyong{ + font-weight: 500; + line-height: 1.2; + border-bottom: unset; + box-shadow:0px 6px 12px 0px rgba(0,0,0,0.1); + border-radius:2px; +} +.yinyin{ + background: #fff; + box-shadow:0px 6px 12px 0px rgba(0,0,0,0.1); + border-radius:2px; +} +.edu-back-eeee{ + background:#EEEEEE !important; +} +.mt-4{ + margin-top: 1.5rem !important; +} + +.statistic-label{ + padding: 2rem 1.25rem; + font-size: 1.5rem; + font-weight: 400 !important; +} +.mb50{ + padding-bottom: 50px !important; +} +.mt40{ + margin-top: 40px; +} +.mb80{ + margin-bottom: 80px; +} +.task-hide{overflow:hidden; white-space: nowrap; text-overflow:ellipsis;} +a:hover{ + color:#0056b3; +} +.color-blue{ + color: #4CACFF; +} + +.color-huang{ + color:#ffc107 !important +} +.maxnamewidth105{ + max-width: 105px; + overflow:hidden; + text-overflow:ellipsis; + white-space:nowrap; + cursor: default; +} +.maxnamewidth247{ + max-width: 247px; + overflow:hidden; + text-overflow:ellipsis; + white-space:nowrap; + cursor: default; +} +.maxnamewidth340{ + max-width: 340px; + overflow:hidden; + text-overflow:ellipsis; + white-space:nowrap; + cursor: default; +} From 95d9635ed4ae1db9acac8e86858fef13005db8c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=9E=97?= <904079904@qq.com> Date: Thu, 19 Dec 2019 14:58:17 +0800 Subject: [PATCH 03/39] =?UTF-8?q?=E6=96=B0=E7=89=88=E5=AD=A6=E9=99=A2?= =?UTF-8?q?=E7=BB=9F=E8=AE=A1=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/react/src/college/College.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/public/react/src/college/College.js b/public/react/src/college/College.js index c503d5387..0f562d00d 100644 --- a/public/react/src/college/College.js +++ b/public/react/src/college/College.js @@ -417,6 +417,8 @@ class College extends Component { student_count:0, shixun_chart_data:null, shixun_chart_datanames:null + studentionsnames:null, + studentionsvalues:null } } From e3f9a0e2fdc75d1b197b46e784c7c2346de969d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=9E=97?= <904079904@qq.com> Date: Thu, 19 Dec 2019 14:58:41 +0800 Subject: [PATCH 04/39] =?UTF-8?q?=E6=96=B0=E7=89=88=E5=AD=A6=E9=99=A2?= =?UTF-8?q?=E7=BB=9F=E8=AE=A1=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/react/src/college/College.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/react/src/college/College.js b/public/react/src/college/College.js index 0f562d00d..2327d5489 100644 --- a/public/react/src/college/College.js +++ b/public/react/src/college/College.js @@ -416,7 +416,7 @@ class College extends Component { students:null, student_count:0, shixun_chart_data:null, - shixun_chart_datanames:null + shixun_chart_datanames:null, studentionsnames:null, studentionsvalues:null } From 074fce56f7d555354aff809aae87828af671a06d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=9E=97?= <904079904@qq.com> Date: Thu, 19 Dec 2019 15:11:24 +0800 Subject: [PATCH 05/39] =?UTF-8?q?=E6=96=B0=E7=89=88=E5=AD=A6=E9=99=A2?= =?UTF-8?q?=E7=BB=9F=E8=AE=A1=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/react/src/college/College.js | 47 +++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 6 deletions(-) diff --git a/public/react/src/college/College.js b/public/react/src/college/College.js index 2327d5489..44649c3cf 100644 --- a/public/react/src/college/College.js +++ b/public/react/src/college/College.js @@ -741,12 +741,30 @@ class College extends Component { const id =this.props.match.params.id; const url=`/colleges/${id}/shixun_chart_data.json`; axios.get(url).then((response) => { + if (response.data.status === 403||response.data.status === 401||response.data.status === 500) { + this.setState({ + shixun_chart_data:[], + shixun_chart_datanames:[] + }) + }else{ + if (response.data.status === -1){ + this.setState({ + shixun_chart_data:[], + shixun_chart_datanames:[] + }) + return + } + this.setState({ shixun_chart_data:response.data.data, shixun_chart_datanames:response.data.names }) + } }).catch((error) => { - + this.setState({ + shixun_chart_data:[], + shixun_chart_datanames:[] + }) }); } //最热测评 @@ -754,12 +772,29 @@ class College extends Component { const id =this.props.match.params.id; const url=`/colleges/${id}/student_hot_evaluations.json`; axios.get(url).then((response) => { + if (response.data.status === 403||response.data.status === 401||response.data.status === 500) { + this.setState({ + studentionsnames: [], + studentionsvalues: [] + }) + }else { + if (response.data.status === -1) { + this.setState({ + studentionsnames: [], + studentionsvalues: [] + }) + return + } + this.setState({ + studentionsnames: response.data.names, + studentionsvalues: response.data.values + }) + } + }).catch((error) => { this.setState({ - studentionsnames:response.data.names, - studentionsvalues:response.data.values + studentionsnames: [], + studentionsvalues: [] }) - }).catch((error) => { - }); } @@ -839,7 +874,7 @@ class College extends Component { </div> </div> </div> - <div className={"educontent edu-back-white"} style={{width: "1200px"}}> + <div className={"educontent edu-back-white mt-4"} style={{width: "1200px"}}> <p className="h4 linjibenshiyong"> 基本使用情况 </p> From 66d3ad03568e923f5480239c88bbb58dbf3d63ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=9E=97?= <904079904@qq.com> Date: Thu, 19 Dec 2019 15:16:42 +0800 Subject: [PATCH 06/39] =?UTF-8?q?=E6=96=B0=E7=89=88=E5=AD=A6=E9=99=A2?= =?UTF-8?q?=E7=BB=9F=E8=AE=A1=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/react/src/college/College.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/public/react/src/college/College.js b/public/react/src/college/College.js index 44649c3cf..eaed9747c 100644 --- a/public/react/src/college/College.js +++ b/public/react/src/college/College.js @@ -299,11 +299,11 @@ class College extends Component { render: (text, record) => ( <span> { - record.id===1? <img width="18px" height="22px" className="mt8" src={getImageUrl("/images/educoder/competition/1.png")}/> + record.id===1? <img width="18px" height="22px" className="mt8" src={getImageUrl("images/educoder/competition/1.png")}/> :record.id===2? - <img width="18px" height="22px" className="mt8" src={getImageUrl("/images/educoder/competition/2.png")}/> + <img width="18px" height="22px" className="mt8" src={getImageUrl("images/educoder/competition/2.png")}/> :record.id===3? - <img width="18px" height="22px" className="mt8" src={getImageUrl("/images/educoder/competition/3.png")}/> + <img width="18px" height="22px" className="mt8" src={getImageUrl("images/educoder/competition/3.png")}/> :record.id } </span> From 04d1d7095d3e980c49ccaebd8efbff2180324f68 Mon Sep 17 00:00:00 2001 From: cxt <853663049@qq.com> Date: Thu, 19 Dec 2019 15:31:19 +0800 Subject: [PATCH 07/39] =?UTF-8?q?=E5=AD=A6=E6=A0=A1=E7=BB=9F=E8=AE=A1?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=E6=9D=83=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/colleges_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/colleges_controller.rb b/app/controllers/colleges_controller.rb index 51a8b7123..2be7f3cd4 100644 --- a/app/controllers/colleges_controller.rb +++ b/app/controllers/colleges_controller.rb @@ -158,7 +158,7 @@ class CollegesController < ApplicationController return true if current_user.admin_or_business? # 超级管理员|运营 return true if current_college.is_a?(Department) && current_college.member?(current_user) # 部门管理员 return true if current_user.is_teacher? && current_user.school_id == current_school.id # 学校老师 - return true if current_school.customers.exists? && current_user.partner&.partner_customers&.exists?(customer_id: current_school.customer_id) + # return true if current_school.customers.exists? && current_user.partner&.partner_customers&.exists?(customer_id: current_school.customer_id) false end From 9c3bff5e9f96170f1b714c199b0760c5bb9aef7f Mon Sep 17 00:00:00 2001 From: cxt <853663049@qq.com> Date: Thu, 19 Dec 2019 15:37:04 +0800 Subject: [PATCH 08/39] =?UTF-8?q?=E5=AD=A6=E6=A0=A1=E7=BB=9F=E8=AE=A1?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=E6=8E=A5=E5=8F=A3=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/colleges_controller.rb | 8 ++++---- app/views/colleges/student_shixun.json.jbuilder | 2 +- app/views/colleges/teachers.json.jbuilder | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/controllers/colleges_controller.rb b/app/controllers/colleges_controller.rb index 2be7f3cd4..707255866 100644 --- a/app/controllers/colleges_controller.rb +++ b/app/controllers/colleges_controller.rb @@ -44,8 +44,8 @@ class CollegesController < ApplicationController (SELECT count(c.id) FROM courses c, course_members m WHERE c.id != 1309 and m.course_id = c.id AND m.user_id=users.id AND m.role in (1,2,3) and c.school_id = #{current_school.id} AND c.is_delete = 0) as course_count FROM `users`, user_extensions ue where ue.school_id=#{current_school.id} and users.id=ue.user_id and ue.identity=0 ORDER BY publish_shixun_count desc, course_count desc, id desc LIMIT 10") # ).order("publish_shixun_count desc, experience desc").limit(10) - @teacher_count = UserExtension.where(school_id: current_school.id) - .select('SUM(IF(identity=0, 1, 0)) AS teachers_count').first.teachers_count + # @teacher_count = UserExtension.where(school_id: current_school.id) + # .select('SUM(IF(identity=0, 1, 0)) AS teachers_count').first.teachers_count @teachers = @teachers.map do |teacher| course_ids = Course.find_by_sql("SELECT c.id FROM courses c, course_members m WHERE c.id != 1309 and m.course_id = c.id AND m.role in (1,2,3) AND m.user_id=#{teacher.id} AND c.is_delete = 0 and c.school_id = #{current_school.id}") @@ -99,7 +99,7 @@ class CollegesController < ApplicationController @course_count = courses.size courses = courses.left_joins(practice_homeworks: { student_works: { myshixun: :games } }) - .select('courses.id, courses.name, courses.is_end, sum(games.evaluate_count) evaluating_count') + .select('courses.id, courses.name, courses.is_end, IFNULL(sum(games.evaluate_count), 0) evaluating_count') .group('courses.id').order('is_end asc, evaluating_count desc') @courses = paginate courses @@ -117,7 +117,7 @@ class CollegesController < ApplicationController # 学生实训 def student_shixun - @student_count = User.joins(:user_extension).where(user_extensions: { school_id: current_school.id, identity: 1 }).count + # @student_count = User.joins(:user_extension).where(user_extensions: { school_id: current_school.id, identity: 1 }).count @students = User.joins(:user_extension).where(user_extensions: { school_id: current_school.id, identity: 1 }).includes(:user_extension).order('experience desc').limit(10) student_ids = @students.map(&:id) diff --git a/app/views/colleges/student_shixun.json.jbuilder b/app/views/colleges/student_shixun.json.jbuilder index 431603afa..97e418148 100644 --- a/app/views/colleges/student_shixun.json.jbuilder +++ b/app/views/colleges/student_shixun.json.jbuilder @@ -7,4 +7,4 @@ json.teachers @students do |student| json.grade student.grade json.experience student.experience end -json.student_count @student_count \ No newline at end of file +# json.student_count @student_count \ No newline at end of file diff --git a/app/views/colleges/teachers.json.jbuilder b/app/views/colleges/teachers.json.jbuilder index 29b383fa4..1308f0cf4 100644 --- a/app/views/colleges/teachers.json.jbuilder +++ b/app/views/colleges/teachers.json.jbuilder @@ -8,4 +8,4 @@ json.teachers @teachers do |teacher| json.complete_rate teacher['complete_rate'] json.publish_shixun_count teacher['publish_shixun_count'] end -json.teacher_count @teacher_count \ No newline at end of file +# json.teacher_count @teacher_count \ No newline at end of file From 3130adbb319c0d0416e5df5864b60bcd23ce0799 Mon Sep 17 00:00:00 2001 From: cxt <853663049@qq.com> Date: Thu, 19 Dec 2019 15:54:11 +0800 Subject: [PATCH 09/39] =?UTF-8?q?=E4=BD=9C=E4=B8=9A=E7=9A=84=E7=8A=B6?= =?UTF-8?q?=E6=80=81=E8=BF=87=E6=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/homework_commons_controller.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/controllers/homework_commons_controller.rb b/app/controllers/homework_commons_controller.rb index 8a1c07ddf..638971dfc 100644 --- a/app/controllers/homework_commons_controller.rb +++ b/app/controllers/homework_commons_controller.rb @@ -167,7 +167,11 @@ class HomeworkCommonsController < ApplicationController if params[:work_status].present? params_work_status = params[:work_status] work_status = params_work_status.map{|status| status.to_i} - @student_works = @student_works.where(compelete_status: work_status) + if @homework.homework_type == "practice" + @student_works = @student_works.where(compelete_status: work_status) + else + @student_works = @student_works.where(work_status: work_status) + end end # 分班情况 From 6567a517cf16f4e07bada8f1b0748d4bd4dc1e3d Mon Sep 17 00:00:00 2001 From: cxt <853663049@qq.com> Date: Thu, 19 Dec 2019 16:36:14 +0800 Subject: [PATCH 10/39] =?UTF-8?q?=E9=A2=98=E5=BA=93=E7=9A=84=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E7=BB=93=E6=9E=84=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/curriculum.rb | 4 ---- app/models/curriculum_direction.rb | 4 ---- app/models/item_bank.rb | 2 -- app/models/knowledge_point.rb | 5 ----- app/models/knowledge_point_container.rb | 3 --- .../20191218070922_create_curriculum_directions.rb | 9 --------- db/migrate/20191218071017_create_curriculums.rb | 10 ---------- db/migrate/20191218071111_create_knowledge_points.rb | 11 ----------- ...191218071343_create_knowledge_point_containers.rb | 12 ------------ spec/models/curriculum_direction_spec.rb | 5 ----- spec/models/curriculum_spec.rb | 5 ----- spec/models/knowledge_point_container_spec.rb | 5 ----- spec/models/knowledge_point_spec.rb | 5 ----- 13 files changed, 80 deletions(-) delete mode 100644 app/models/curriculum.rb delete mode 100644 app/models/curriculum_direction.rb delete mode 100644 app/models/knowledge_point.rb delete mode 100644 app/models/knowledge_point_container.rb delete mode 100644 db/migrate/20191218070922_create_curriculum_directions.rb delete mode 100644 db/migrate/20191218071017_create_curriculums.rb delete mode 100644 db/migrate/20191218071111_create_knowledge_points.rb delete mode 100644 db/migrate/20191218071343_create_knowledge_point_containers.rb delete mode 100644 spec/models/curriculum_direction_spec.rb delete mode 100644 spec/models/curriculum_spec.rb delete mode 100644 spec/models/knowledge_point_container_spec.rb delete mode 100644 spec/models/knowledge_point_spec.rb diff --git a/app/models/curriculum.rb b/app/models/curriculum.rb deleted file mode 100644 index 0b78814bc..000000000 --- a/app/models/curriculum.rb +++ /dev/null @@ -1,4 +0,0 @@ -class Curriculum < ApplicationRecord - belongs_to :curriculum_direction - has_many :knowledge_points, dependent: :destroy -end diff --git a/app/models/curriculum_direction.rb b/app/models/curriculum_direction.rb deleted file mode 100644 index 1c9211559..000000000 --- a/app/models/curriculum_direction.rb +++ /dev/null @@ -1,4 +0,0 @@ -class CurriculumDirection < ApplicationRecord - has_many :curriculums - has_many :knowledge_points -end diff --git a/app/models/item_bank.rb b/app/models/item_bank.rb index 32c349e34..8078a55e0 100644 --- a/app/models/item_bank.rb +++ b/app/models/item_bank.rb @@ -3,8 +3,6 @@ class ItemBank < ApplicationRecord # item_type: 0 单选 1 多选 2 判断 3 填空 4 简答 5 实训 6 编程 enum item_type: { SINGLE: 0, MULTIPLE: 1, JUDGMENT: 2, COMPLETION: 3, SUBJECTIVE: 4, PRACTICAL: 5, PROGRAM: 6 } - belongs_to :curriculum - belongs_to :curriculum_direction belongs_to :user has_one :item_analysis, dependent: :destroy diff --git a/app/models/knowledge_point.rb b/app/models/knowledge_point.rb deleted file mode 100644 index 3d75b66a1..000000000 --- a/app/models/knowledge_point.rb +++ /dev/null @@ -1,5 +0,0 @@ -class KnowledgePoint < ApplicationRecord - belongs_to :curriculum_direction - belongs_to :curriculum - has_many :knowledge_point_containers, dependent: :destroy -end diff --git a/app/models/knowledge_point_container.rb b/app/models/knowledge_point_container.rb deleted file mode 100644 index ea73d00e7..000000000 --- a/app/models/knowledge_point_container.rb +++ /dev/null @@ -1,3 +0,0 @@ -class KnowledgePointContainer < ApplicationRecord - belongs_to :knowledge_point -end diff --git a/db/migrate/20191218070922_create_curriculum_directions.rb b/db/migrate/20191218070922_create_curriculum_directions.rb deleted file mode 100644 index 9203aa435..000000000 --- a/db/migrate/20191218070922_create_curriculum_directions.rb +++ /dev/null @@ -1,9 +0,0 @@ -class CreateCurriculumDirections < ActiveRecord::Migration[5.2] - def change - create_table :curriculum_directions do |t| - t.string :name - - t.timestamps - end - end -end diff --git a/db/migrate/20191218071017_create_curriculums.rb b/db/migrate/20191218071017_create_curriculums.rb deleted file mode 100644 index 885f2a676..000000000 --- a/db/migrate/20191218071017_create_curriculums.rb +++ /dev/null @@ -1,10 +0,0 @@ -class CreateCurriculums < ActiveRecord::Migration[5.2] - def change - create_table :curriculums do |t| - t.string :name - t.references :curriculum_direction, index: true - - t.timestamps - end - end -end diff --git a/db/migrate/20191218071111_create_knowledge_points.rb b/db/migrate/20191218071111_create_knowledge_points.rb deleted file mode 100644 index 2f748d266..000000000 --- a/db/migrate/20191218071111_create_knowledge_points.rb +++ /dev/null @@ -1,11 +0,0 @@ -class CreateKnowledgePoints < ActiveRecord::Migration[5.2] - def change - create_table :knowledge_points do |t| - t.string :name - t.references :curriculum_direction, index: true - t.references :curriculum, index: true - - t.timestamps - end - end -end diff --git a/db/migrate/20191218071343_create_knowledge_point_containers.rb b/db/migrate/20191218071343_create_knowledge_point_containers.rb deleted file mode 100644 index 0b6944ea7..000000000 --- a/db/migrate/20191218071343_create_knowledge_point_containers.rb +++ /dev/null @@ -1,12 +0,0 @@ -class CreateKnowledgePointContainers < ActiveRecord::Migration[5.2] - def change - create_table :knowledge_point_containers do |t| - t.references :knowledge_point - t.integer :container_id - t.string :container_type - - t.timestamps - end - add_index :knowledge_point_containers, [:knowledge_point_id, :container_id, :container_type], name: "container_index", unique: true - end -end diff --git a/spec/models/curriculum_direction_spec.rb b/spec/models/curriculum_direction_spec.rb deleted file mode 100644 index 40cab64ca..000000000 --- a/spec/models/curriculum_direction_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'rails_helper' - -RSpec.describe CurriculumDirection, type: :model do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/models/curriculum_spec.rb b/spec/models/curriculum_spec.rb deleted file mode 100644 index b03089a91..000000000 --- a/spec/models/curriculum_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'rails_helper' - -RSpec.describe Curriculum, type: :model do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/models/knowledge_point_container_spec.rb b/spec/models/knowledge_point_container_spec.rb deleted file mode 100644 index 3e151062f..000000000 --- a/spec/models/knowledge_point_container_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'rails_helper' - -RSpec.describe KnowledgePointContainer, type: :model do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/models/knowledge_point_spec.rb b/spec/models/knowledge_point_spec.rb deleted file mode 100644 index d85138a0f..000000000 --- a/spec/models/knowledge_point_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'rails_helper' - -RSpec.describe KnowledgePoint, type: :model do - pending "add some examples to (or delete) #{__FILE__}" -end From e47eda0150a8bc51f7a12f56f31876405243169f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=9E=97?= <904079904@qq.com> Date: Thu, 19 Dec 2019 16:53:50 +0800 Subject: [PATCH 11/39] =?UTF-8?q?=E6=96=B0=E7=89=88=E5=AD=A6=E9=99=A2?= =?UTF-8?q?=E7=BB=9F=E8=AE=A1=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/react/src/AppConfig.js | 38 +++++++++---------- public/react/src/college/College.js | 8 ++-- .../college/colleagechart/Colleagechart.js | 6 +-- .../college/colleagechart/Colleagechartzu.js | 6 +-- 4 files changed, 29 insertions(+), 29 deletions(-) diff --git a/public/react/src/AppConfig.js b/public/react/src/AppConfig.js index ac39562a7..c51c0d5e1 100644 --- a/public/react/src/AppConfig.js +++ b/public/react/src/AppConfig.js @@ -19,25 +19,25 @@ function locationurl(list){ let hashTimeout // TODO 开发期多个身份切换 -let debugType ="" -if (isDev) { - const _search = window.location.search; - let parsed = {}; - if (_search) { - parsed = queryString.parse(_search); - } - debugType = window.location.search.indexOf('debug=t') != -1 ? 'teacher' : - window.location.search.indexOf('debug=s') != -1 ? 'student' : - window.location.search.indexOf('debug=a') != -1 ? 'admin' : parsed.debug || 'admin' -} -// 超管 -// debugType="admin"; -// 老师 -//ebugType="teacher"; -// 学生 -// debugType="student"; - -window._debugType = debugType; +// let debugType ="" +// if (isDev) { +// const _search = window.location.search; +// let parsed = {}; +// if (_search) { +// parsed = queryString.parse(_search); +// } +// debugType = window.location.search.indexOf('debug=t') != -1 ? 'teacher' : +// window.location.search.indexOf('debug=s') != -1 ? 'student' : +// window.location.search.indexOf('debug=a') != -1 ? 'admin' : parsed.debug || 'admin' +// } +// // 超管 +// // debugType="admin"; +// // 老师 +// //ebugType="teacher"; +// // 学生 +// // debugType="student"; +// +// window._debugType = debugType; export function initAxiosInterceptors(props) { initOnlineOfflineListener() diff --git a/public/react/src/college/College.js b/public/react/src/college/College.js index eaed9747c..c204ab65b 100644 --- a/public/react/src/college/College.js +++ b/public/react/src/college/College.js @@ -1037,7 +1037,7 @@ class College extends Component { <div className={"educontent edu-back-white yinyin mt-4 sortinxdirection"} style={{width: "1200px"}}> <div className=" verticallayout" style={{ - width: "65%" + width: "63%" }}> <p className="statistic-label ysllinjibenshiyong yinyin"> 教师排名 @@ -1112,7 +1112,7 @@ class College extends Component { </div> <div className="" style={{ - width: "35%" + width: "37%" }}><div className="yslslinjibenshiyong" style={{ height: "100%" }}> @@ -1145,7 +1145,7 @@ class College extends Component { <div className={"educontent edu-back-white yinyin mt-4 sortinxdirection mb80"} style={{width: "1200px"}}> <div className=" verticallayout" style={{ - width: "65%" + width: "63%" }}> <p className="statistic-label ysllinjibenshiyong yinyin "> 学生排名 @@ -1218,7 +1218,7 @@ class College extends Component { </div> <div className="" style={{ - width: "35%" + width: "37%" }}> <div className="yslslinjibenshiyong" style={{ diff --git a/public/react/src/college/colleagechart/Colleagechart.js b/public/react/src/college/colleagechart/Colleagechart.js index 1e2767f5a..619c34db4 100644 --- a/public/react/src/college/colleagechart/Colleagechart.js +++ b/public/react/src/college/colleagechart/Colleagechart.js @@ -13,12 +13,12 @@ function startechart(data,datanane){ tooltip : { trigger: 'item', - formatter: "{a} <br/>{b} : {c} ({d}%)" + formatter: "{d}% <br/>" }, legend: { // orient: 'vertical', // top: 'middle', - bottom: 40, + bottom: 50, left: 'center', data: datanane }, @@ -68,7 +68,7 @@ class Colleagechart extends Component { <div> <div - style={{ width:'410px',height:'600px'}} + style={{ width:'440px',height:'600px'}} id="shixun_skill_chart"> </div> diff --git a/public/react/src/college/colleagechart/Colleagechartzu.js b/public/react/src/college/colleagechart/Colleagechartzu.js index c65d2f6f2..ff1b6fb6b 100644 --- a/public/react/src/college/colleagechart/Colleagechartzu.js +++ b/public/react/src/college/colleagechart/Colleagechartzu.js @@ -15,8 +15,8 @@ function startechart(names, values){ backgroundColor: '#fff', grid: { left: '3%', - right: '4%', - bottom: '10%', + right: '10%', + bottom: '15%', containLabel: true }, @@ -133,7 +133,7 @@ class Colleagechartzu extends Component { <div> <div - style={{ width:'410px',height:'600px'}} + style={{ width:'440px',height:'600px'}} id="shixun_skill_charts"> </div> From a0af31b2455869f5e654a58312eac490e2a10300 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=9E=97?= <904079904@qq.com> Date: Thu, 19 Dec 2019 16:54:09 +0800 Subject: [PATCH 12/39] =?UTF-8?q?=E6=96=B0=E7=89=88=E5=AD=A6=E9=99=A2?= =?UTF-8?q?=E7=BB=9F=E8=AE=A1=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/react/src/AppConfig.js | 38 +++++++++++++++++------------------ 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/public/react/src/AppConfig.js b/public/react/src/AppConfig.js index c51c0d5e1..ac39562a7 100644 --- a/public/react/src/AppConfig.js +++ b/public/react/src/AppConfig.js @@ -19,25 +19,25 @@ function locationurl(list){ let hashTimeout // TODO 开发期多个身份切换 -// let debugType ="" -// if (isDev) { -// const _search = window.location.search; -// let parsed = {}; -// if (_search) { -// parsed = queryString.parse(_search); -// } -// debugType = window.location.search.indexOf('debug=t') != -1 ? 'teacher' : -// window.location.search.indexOf('debug=s') != -1 ? 'student' : -// window.location.search.indexOf('debug=a') != -1 ? 'admin' : parsed.debug || 'admin' -// } -// // 超管 -// // debugType="admin"; -// // 老师 -// //ebugType="teacher"; -// // 学生 -// // debugType="student"; -// -// window._debugType = debugType; +let debugType ="" +if (isDev) { + const _search = window.location.search; + let parsed = {}; + if (_search) { + parsed = queryString.parse(_search); + } + debugType = window.location.search.indexOf('debug=t') != -1 ? 'teacher' : + window.location.search.indexOf('debug=s') != -1 ? 'student' : + window.location.search.indexOf('debug=a') != -1 ? 'admin' : parsed.debug || 'admin' +} +// 超管 +// debugType="admin"; +// 老师 +//ebugType="teacher"; +// 学生 +// debugType="student"; + +window._debugType = debugType; export function initAxiosInterceptors(props) { initOnlineOfflineListener() From 0a34988f409da02fed284eca16afb6daeba5decb Mon Sep 17 00:00:00 2001 From: jingquan huang <huang.jingquan@163.com> Date: Thu, 19 Dec 2019 17:05:57 +0800 Subject: [PATCH 13/39] =?UTF-8?q?=E5=AE=9E=E9=AA=8C=E7=8E=AF=E5=A2=83?= =?UTF-8?q?=E4=B8=BA=E7=A9=BA=E7=9A=84=E6=8F=90=E9=86=92=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/myshixuns_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/myshixuns_controller.rb b/app/controllers/myshixuns_controller.rb index 987f4873a..0e9ba477a 100644 --- a/app/controllers/myshixuns_controller.rb +++ b/app/controllers/myshixuns_controller.rb @@ -247,7 +247,7 @@ class MyshixunsController < ApplicationController def update_file begin @hide_code = Shixun.where(id: @myshixun.shixun_id).pluck(:hide_code).first - tip_exception("技术平台为空!") if @myshixun.mirror_name.blank? + tip_exception("实验环境不能为空,请查看实训模板的环境配置项是否正确!") if (@myshixun.mirror_name.blank? || @myshixun.mirror_name.first.to_s == "-1") path = params[:path].strip unless params[:path].blank? game_id = params[:game_id] game = Game.find(game_id) From 85bc2079d2578e8a9cac29ccccc53a1ecd02cbca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=9E=97?= <904079904@qq.com> Date: Thu, 19 Dec 2019 17:13:26 +0800 Subject: [PATCH 14/39] =?UTF-8?q?=E6=96=B0=E7=89=88=E5=AD=A6=E9=99=A2?= =?UTF-8?q?=E7=BB=9F=E8=AE=A1=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/react/src/college/College.js | 14 +++++++------- .../src/college/colleagechart/Colleagechart.js | 2 +- .../src/college/colleagechart/Colleagechartzu.js | 4 ++-- public/react/src/college/colleagecss/colleage.css | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/public/react/src/college/College.js b/public/react/src/college/College.js index c204ab65b..bc43252b7 100644 --- a/public/react/src/college/College.js +++ b/public/react/src/college/College.js @@ -824,8 +824,8 @@ class College extends Component { <div className="newMain clearfix edu-back-eeee"> <div className="yslstatistic-header intermediatecenter" > <div className="intermediatecenter " style={{ - maxWidth:"1200px", - width:"1200px", + maxWidth:"1300px", + width:"1300px", height: '100%', }}> <div className="yslstatistic-header-title">{school}</div> @@ -874,7 +874,7 @@ class College extends Component { </div> </div> </div> - <div className={"educontent edu-back-white mt-4"} style={{width: "1200px"}}> + <div className={"educontent edu-back-white mt-4"} style={{width: "1300px"}}> <p className="h4 linjibenshiyong"> 基本使用情况 </p> @@ -956,7 +956,7 @@ class College extends Component { </div> - <div className={"educontent edu-back-white mt-4 yinyin"} style={{width: "1200px"}}> + <div className={"educontent edu-back-white mt-4 yinyin"} style={{width: "1300px"}}> <p className="statistic-label linjibenshiyong"> 课堂 </p> @@ -974,7 +974,7 @@ class College extends Component { </NoneData> : - <div style={{width: "1200px"}}> + <div style={{width: "1300px"}}> <div className={"justify break_full_word new_li edu-back-white"} style={{minHeight: "480px"}}> <style>{` @@ -1035,7 +1035,7 @@ class College extends Component { </div> - <div className={"educontent edu-back-white yinyin mt-4 sortinxdirection"} style={{width: "1200px"}}> + <div className={"educontent edu-back-white yinyin mt-4 sortinxdirection"} style={{width: "1300px"}}> <div className=" verticallayout" style={{ width: "63%" }}> @@ -1143,7 +1143,7 @@ class College extends Component { </div> - <div className={"educontent edu-back-white yinyin mt-4 sortinxdirection mb80"} style={{width: "1200px"}}> + <div className={"educontent edu-back-white yinyin mt-4 sortinxdirection mb80"} style={{width: "1300px"}}> <div className=" verticallayout" style={{ width: "63%" }}> diff --git a/public/react/src/college/colleagechart/Colleagechart.js b/public/react/src/college/colleagechart/Colleagechart.js index 619c34db4..fca01280a 100644 --- a/public/react/src/college/colleagechart/Colleagechart.js +++ b/public/react/src/college/colleagechart/Colleagechart.js @@ -68,7 +68,7 @@ class Colleagechart extends Component { <div> <div - style={{ width:'440px',height:'600px'}} + style={{ width:'100%',height:'600px'}} id="shixun_skill_chart"> </div> diff --git a/public/react/src/college/colleagechart/Colleagechartzu.js b/public/react/src/college/colleagechart/Colleagechartzu.js index ff1b6fb6b..5c0269700 100644 --- a/public/react/src/college/colleagechart/Colleagechartzu.js +++ b/public/react/src/college/colleagechart/Colleagechartzu.js @@ -15,7 +15,7 @@ function startechart(names, values){ backgroundColor: '#fff', grid: { left: '3%', - right: '10%', + right: '8%', bottom: '15%', containLabel: true }, @@ -133,7 +133,7 @@ class Colleagechartzu extends Component { <div> <div - style={{ width:'440px',height:'600px'}} + style={{ width:'100%',height:'600px'}} id="shixun_skill_charts"> </div> diff --git a/public/react/src/college/colleagecss/colleage.css b/public/react/src/college/colleagecss/colleage.css index 031396896..801b86603 100644 --- a/public/react/src/college/colleagecss/colleage.css +++ b/public/react/src/college/colleagecss/colleage.css @@ -31,7 +31,7 @@ } .yslstatistic-base-item-label{ - width: 200px; + width: 217px; text-align: center; font-size: 16px; height: 48px; @@ -41,7 +41,7 @@ border-top: 1px solid #EBEBEB; } .yslstatistic-base-item-labels{ - width: 200px; + width: 217px; text-align: center; height: 100px; line-height: 100px; From 758ea539b2126c50b98a6f8b1bc48c871fd42070 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=98=8E?= <775174143@qq.com> Date: Thu, 19 Dec 2019 17:49:34 +0800 Subject: [PATCH 15/39] =?UTF-8?q?=E5=AE=9E=E8=AE=AD=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/react/src/modules/tpm/TPMBanner.js | 3 +++ public/react/src/modules/tpm/TPMIndex.js | 3 +++ .../modules/tpm/TPMsettings/LearningSettings.js | 6 +++--- .../modules/tpm/TPMsettings/Shixuninformation.js | 10 +++++++++- .../src/modules/tpm/component/TPMRightSection.js | 6 ++++-- .../tpm/shixunchild/Challenges/Challenges.js | 15 ++++++++++----- .../shixunchild/Collaborators/Collaborators.css | 9 +++++++++ .../shixunchild/Collaborators/Collaborators.js | 6 ++---- .../src/modules/tpm/shixuns/ShixunCardList.js | 2 +- 9 files changed, 44 insertions(+), 16 deletions(-) diff --git a/public/react/src/modules/tpm/TPMBanner.js b/public/react/src/modules/tpm/TPMBanner.js index a31ca5952..141bd87d9 100644 --- a/public/react/src/modules/tpm/TPMBanner.js +++ b/public/react/src/modules/tpm/TPMBanner.js @@ -796,6 +796,9 @@ class TPMBanner extends Component { height: 180px !important; padding-top:35px !important; } + .ant-popover{ + z-index:1000 !important; + } ` } </style> diff --git a/public/react/src/modules/tpm/TPMIndex.js b/public/react/src/modules/tpm/TPMIndex.js index d79bae95b..e032bb91f 100644 --- a/public/react/src/modules/tpm/TPMIndex.js +++ b/public/react/src/modules/tpm/TPMIndex.js @@ -385,6 +385,9 @@ class TPMIndex extends Component { margin:0 40px 0 0; padding:0px; } + .ant-popover{ + z-index:1000 !important; + } ` } </style> diff --git a/public/react/src/modules/tpm/TPMsettings/LearningSettings.js b/public/react/src/modules/tpm/TPMsettings/LearningSettings.js index 681cbc956..a98f68223 100644 --- a/public/react/src/modules/tpm/TPMsettings/LearningSettings.js +++ b/public/react/src/modules/tpm/TPMsettings/LearningSettings.js @@ -215,9 +215,9 @@ export default class Shixuninformation extends Component { multi_webssh: false }) } else { - this.setState({ - multi_webssh: true - }) + // this.setState({ + // multi_webssh: true + // }) } this.setState({ opensshRadio: e.target.value diff --git a/public/react/src/modules/tpm/TPMsettings/Shixuninformation.js b/public/react/src/modules/tpm/TPMsettings/Shixuninformation.js index 200880019..75ed88852 100644 --- a/public/react/src/modules/tpm/TPMsettings/Shixuninformation.js +++ b/public/react/src/modules/tpm/TPMsettings/Shixuninformation.js @@ -50,7 +50,10 @@ class Shixuninformation extends Component { } componentDidMount() { - + let anchorElement = document.getElementById("newcourseContentMD"); + if(anchorElement){ + this.scrollToAnchor("newcourseContentMD"); + } } componentDidUpdate(prevProps, prevState) { @@ -113,6 +116,7 @@ class Shixuninformation extends Component { selectright: this.props.data && this.props.data.shixun.choice_small_type, }) this.contentMdRef.current.setValue(this.props.data && this.props.data.shixun.description); + } } } @@ -807,16 +811,20 @@ class Shixuninformation extends Component { )} </Form.Item> + <span id={"newcourseContentMD"}></span> <Form.Item label="简介" style={{"borderBottom": 'none', 'marginBottom': '0px'}} className="chooseDes pr" + > + <TPMMDEditor ref={this.contentMdRef} placeholder="请输入简介" mdID={'courseContentMD'} refreshTimeout={1500} className="courseMessageMD" // initValue={this.state.description === null ? "" : this.state.description} ></TPMMDEditor> + </Form.Item> diff --git a/public/react/src/modules/tpm/component/TPMRightSection.js b/public/react/src/modules/tpm/component/TPMRightSection.js index 1d2a93796..88894794b 100644 --- a/public/react/src/modules/tpm/component/TPMRightSection.js +++ b/public/react/src/modules/tpm/component/TPMRightSection.js @@ -63,6 +63,8 @@ class TPMRightSection extends Component { if(TPMRightSectionData&&TPMRightSectionData.complete_count!=null){ Progresssum=(parseInt(TPMRightSectionData&&TPMRightSectionData.complete_count) / parseInt(TPMRightSectionData&&TPMRightSectionData.challenge_count))*100; } + + return ( <div> { @@ -97,11 +99,11 @@ class TPMRightSection extends Component { </div> </div> - {TPMRightSectionData&&TPMRightSectionData.complete_count!=null?<div className="edu-back-white padd252020px relative borderbottomf4"> + {this.props&&this.props.status>1?<div className="edu-back-white padd252020px relative borderbottomf4"> <div className="font-16 mb5"> <span><i className={"iconfont icon-jilu1 audit_situationactive font-14"}></i> 学习统计</span> <span className={"sortinxdirection space-between fr"}> - <span className="color888hezuo font-12">已完成 {TPMRightSectionData&&TPMRightSectionData.complete_count} 个 / 共 {TPMRightSectionData&&TPMRightSectionData.challenge_count} 关</span> + <span className="color888hezuo font-12">已完成 {TPMRightSectionData&&TPMRightSectionData.complete_count===null?0:TPMRightSectionData&&TPMRightSectionData.complete_count} 个 / 共 {TPMRightSectionData&&TPMRightSectionData.challenge_count} 关</span> </span> </div> diff --git a/public/react/src/modules/tpm/shixunchild/Challenges/Challenges.js b/public/react/src/modules/tpm/shixunchild/Challenges/Challenges.js index 307823ee8..e7b7ef261 100644 --- a/public/react/src/modules/tpm/shixunchild/Challenges/Challenges.js +++ b/public/react/src/modules/tpm/shixunchild/Challenges/Challenges.js @@ -34,7 +34,8 @@ class Challenges extends Component { operationstrue:false, isSpin:false, boxoffsetHeigh:0, - opentitletype:true + opentitletype:true, + isopentitletype:"Less", } } @@ -73,15 +74,17 @@ class Challenges extends Component { boxoffsetHeigh=box.offsetHeight if(boxoffsetHeigh<260){ this.setState({ - opentitletype:false, + isopentitletype:"Less", boxoffsetHeigh:boxoffsetHeigh }) }else{ this.setState({ + opentitletype:true, + isopentitletype:"greater", boxoffsetHeigh:boxoffsetHeigh }) } - + console.log(boxoffsetHeigh) } } @@ -322,7 +325,8 @@ class Challenges extends Component { opentitle=()=>{ this.setState({ - opentitletype:!this.state.opentitletype + opentitletype:!this.state.opentitletype, + }) } @@ -434,7 +438,8 @@ class Challenges extends Component { </p> </div> </div> - {this.state.opentitletype===true?<Divider dashed={true} onClick={()=>this.opentitle()} className={"pointer Breadcrumbfont color-grey-9 "}> + + {this.state.isopentitletype==="Less"?"":this.state.opentitletype===true?<Divider dashed={true} onClick={()=>this.opentitle()} className={"pointer Breadcrumbfont color-grey-9 "}> <a className={"font-14 color-grey-9"}>阅读全文 <i className={"iconfont icon-jiantou9 font-14"}></i></a> </Divider>:<Divider dashed={true} onClick={()=>this.opentitle()} className={"pointer Breadcrumbfont color-grey-9 "}> <a className={"font-14 color-grey-9"}>收起全文 <i className={"iconfont icon-changyongtubiao-xianxingdaochu-zhuanqu- font-14"}></i></a> diff --git a/public/react/src/modules/tpm/shixunchild/Collaborators/Collaborators.css b/public/react/src/modules/tpm/shixunchild/Collaborators/Collaborators.css index 688dbb422..b059ab406 100644 --- a/public/react/src/modules/tpm/shixunchild/Collaborators/Collaborators.css +++ b/public/react/src/modules/tpm/shixunchild/Collaborators/Collaborators.css @@ -184,4 +184,13 @@ .fontneweees { color: #BBBBBB; +} + +.maxfont450{ + width: 450px; + max-width:450px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + cursor: default; } \ No newline at end of file diff --git a/public/react/src/modules/tpm/shixunchild/Collaborators/Collaborators.js b/public/react/src/modules/tpm/shixunchild/Collaborators/Collaborators.js index 15a956a0b..17b083cf7 100644 --- a/public/react/src/modules/tpm/shixunchild/Collaborators/Collaborators.js +++ b/public/react/src/modules/tpm/shixunchild/Collaborators/Collaborators.js @@ -11,11 +11,9 @@ import NoneData from "../../../courses/coursesPublic/NoneData"; import './Collaborators.css'; -const $ = window.$; - const RadioGroup = Radio.Group; -const Search = Input.Search; + class Collaborators extends Component { constructor(props) { @@ -685,7 +683,7 @@ class Collaborators extends Component { <p className="hezuozhe630 sortinxdirection space-between"> {/*<p className={item.user.identity===null||item.user.identity===undefined||item.user.identity===""?" font-16 ":"mr20 font-16 w70"}>{item.user.identity}</p>*/} <p - className={item.user.school_name === null || item.user.school_name === "" ? "" : "mr40 font-16 maxnamewidth150 color888hezuo"}>{item.user.school_name}</p> + className={item.user.school_name === null || item.user.school_name === "" ? "" : " font-16 color888hezuo maxfont450"}>{item.user.school_name}</p> <p className="fabushixunwidth color888hezuo">发布实训项目 <span className="ml2">{item.user.user_shixuns_count}</span></p> </p> diff --git a/public/react/src/modules/tpm/shixuns/ShixunCardList.js b/public/react/src/modules/tpm/shixuns/ShixunCardList.js index 3676ed361..937e96894 100644 --- a/public/react/src/modules/tpm/shixuns/ShixunCardList.js +++ b/public/react/src/modules/tpm/shixuns/ShixunCardList.js @@ -218,7 +218,7 @@ class ShixunCardList extends Component { id="hot" onClick={(e)=>this.latestHot(e,3)}>最热 </div> - {shixuntype===true?"":<span className={ "fl font-16 bestChoose color-blue" } onClick={(url)=>this.getUser("/shixuns/new")}>+新建实训项目</span>} + {shixuntype===true?"":<span className={ "fr font-16 bestChoose color-blue" } onClick={(url)=>this.getUser("/shixuns/new")}>+新建实训项目</span>} {/*<div className="fl font-16 bestChoose shixun_repertoire ml20 mt1"*/} {/*style={{display:upcircle===true?"block":"none"}}*/} From 53ad771fae8ad4a44cbc61bbe8125ff472fd5c9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=98=8E?= <775174143@qq.com> Date: Thu, 19 Dec 2019 17:55:39 +0800 Subject: [PATCH 16/39] =?UTF-8?q?=E5=AE=9E=E8=AE=AD=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/react/src/modules/tpm/challengesnew/TPManswer.js | 4 ++-- public/react/src/modules/tpm/challengesnew/TPManswer2.js | 4 ++-- .../react/src/modules/tpm/challengesnew/TPMchallengesnew.js | 4 ++-- public/react/src/modules/tpm/challengesnew/TPMevaluation.js | 4 ++-- public/react/src/modules/tpm/challengesnew/TPMquestion.js | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/public/react/src/modules/tpm/challengesnew/TPManswer.js b/public/react/src/modules/tpm/challengesnew/TPManswer.js index 9c9a23a12..9187e09b0 100644 --- a/public/react/src/modules/tpm/challengesnew/TPManswer.js +++ b/public/react/src/modules/tpm/challengesnew/TPManswer.js @@ -302,11 +302,11 @@ export default class TPManswer extends Component { className="color-grey-6 fr font-15 mt3">返回</Link> {prev_challenge === undefined ? "" : - <Link to={prev_challenge} className="fr color-blue mr15 mt4">上一关</Link> + <a href={prev_challenge} className="fr color-blue mr15 mt4">上一关</a> } {next_challenge === undefined ? "" : - <Link to={next_challenge} className="fr color-blue mr15 mt4">下一关</Link> + <a href={next_challenge} className="fr color-blue mr15 mt4">下一关</a> } <a href={practice_url === undefined ? "" : practice_url} diff --git a/public/react/src/modules/tpm/challengesnew/TPManswer2.js b/public/react/src/modules/tpm/challengesnew/TPManswer2.js index 17e429199..dfdc58db4 100644 --- a/public/react/src/modules/tpm/challengesnew/TPManswer2.js +++ b/public/react/src/modules/tpm/challengesnew/TPManswer2.js @@ -265,11 +265,11 @@ export default class TPManswer extends Component { className="color-grey-6 fr font-15 mt3">返回</Link> {prev_challenge === undefined ? "" : - <Link to={prev_challenge} className="fr color-blue mr15 mt4">上一关</Link> + <a href={prev_challenge} className="fr color-blue mr15 mt4">上一关</a> } {next_challenge === undefined ? "" : - <Link to={next_challenge} className="fr color-blue mr15 mt4">下一关</Link> + <a href={next_challenge} className="fr color-blue mr15 mt4">下一关</a> } <a href={practice_url === undefined ? "" : practice_url} diff --git a/public/react/src/modules/tpm/challengesnew/TPMchallengesnew.js b/public/react/src/modules/tpm/challengesnew/TPMchallengesnew.js index 50b5c8106..f6bac13a5 100644 --- a/public/react/src/modules/tpm/challengesnew/TPMchallengesnew.js +++ b/public/react/src/modules/tpm/challengesnew/TPMchallengesnew.js @@ -429,10 +429,10 @@ export default class TPMchallengesnew extends Component { <Link to={go_back_url === undefined ? "" : go_back_url} className="color-grey-6 fr font-15 mt3">返回</Link> { next_challenge===undefined?"": - <Link to={next_challenge}className="fr color-blue mr15 mt4">下一关</Link> + <a href={next_challenge}className="fr color-blue mr15 mt4">下一关</a> } { prev_challenge===undefined?"": - <Link to={prev_challenge} className="fr color-blue mr15 mt4">上一关</Link> + <a href={prev_challenge} className="fr color-blue mr15 mt4">上一关</a> } diff --git a/public/react/src/modules/tpm/challengesnew/TPMevaluation.js b/public/react/src/modules/tpm/challengesnew/TPMevaluation.js index d70f22a0a..34eb1a075 100644 --- a/public/react/src/modules/tpm/challengesnew/TPMevaluation.js +++ b/public/react/src/modules/tpm/challengesnew/TPMevaluation.js @@ -824,11 +824,11 @@ export default class TPMevaluation extends Component { className="color-grey-6 fr font-15 mt3">返回</Link> {prev_challenge === undefined ? "" : - <Link to={prev_challenge} className="fr color-blue mr15 mt4">上一关</Link> + <a href={prev_challenge} className="fr color-blue mr15 mt4">上一关</a> } {next_challenge === undefined ? "" : - <Link to={next_challenge} className="fr color-blue mr15 mt4">下一关</Link> + <a href={next_challenge} className="fr color-blue mr15 mt4">下一关</a> } <a href={practice_url === undefined ? "" : practice_url} diff --git a/public/react/src/modules/tpm/challengesnew/TPMquestion.js b/public/react/src/modules/tpm/challengesnew/TPMquestion.js index 645077fea..b76e17b17 100644 --- a/public/react/src/modules/tpm/challengesnew/TPMquestion.js +++ b/public/react/src/modules/tpm/challengesnew/TPMquestion.js @@ -936,11 +936,11 @@ export default class TPMquestion extends Component { <Link to={go_back_url === undefined ? "" : go_back_url} className="color-grey-6 fr font-15 mt3">返回</Link> { prev_challenge===undefined?"": - <Link to={prev_challenge} className="fr color-blue mr15 mt4">上一关</Link> + <a href={prev_challenge} className="fr color-blue mr15 mt4">上一关</a> } { next_challenge===undefined?"": - <Link to={next_challenge}className="fr color-blue mr15 mt4">下一关</Link> + <a href={next_challenge}className="fr color-blue mr15 mt4">下一关</a> } <a href={practice_url === undefined ? "" : practice_url} From 1f0f26eb6576282c0e8414bf2db866daa5a02442 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=98=8E?= <775174143@qq.com> Date: Thu, 19 Dec 2019 18:02:44 +0800 Subject: [PATCH 17/39] =?UTF-8?q?=E5=AE=9E=E8=AE=AD=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/react/src/modules/tpm/component/TPMright.css | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/public/react/src/modules/tpm/component/TPMright.css b/public/react/src/modules/tpm/component/TPMright.css index a75160bf5..0d6b306fd 100644 --- a/public/react/src/modules/tpm/component/TPMright.css +++ b/public/react/src/modules/tpm/component/TPMright.css @@ -119,9 +119,14 @@ .padd252020px{ padding: 25px 20px 15px; } + .rightjinengs{ height: 35px; margin-top: 20px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; } .borderbottomf4{ From 0712932812985d2486b2f2c3cc9647ddb598742e Mon Sep 17 00:00:00 2001 From: tangjiang <465264938@qq.com> Date: Thu, 19 Dec 2019 18:03:42 +0800 Subject: [PATCH 18/39] update oj --- public/react/package.json | 1 + .../common/components/comment/CommentForm.js | 116 ++++++++++++ .../common/components/comment/CommentIcon.js | 32 ++++ .../common/components/comment/CommentItem.js | 165 +++++++++++++++++ .../common/components/comment/CommentList.js | 20 +++ .../src/common/components/comment/index.js | 22 +++ .../src/common/components/comment/index.scss | 111 ++++++++++++ .../src/common/quillForEditor/ImageBlot.js | 54 ++++++ .../src/common/quillForEditor/deepEqual.js | 47 +++++ .../react/src/common/quillForEditor/index.js | 166 ++++++++++++++++++ .../react/src/common/reactQuill/ImageBlot.js | 54 ++++++ .../react/src/common/reactQuill/ReactQuill.js | 45 +++++ .../react/src/common/reactQuill/deepEqual.js | 47 +++++ public/react/src/common/reactQuill/flatten.js | 26 +++ public/react/src/common/reactQuill/index.js | 108 ++++++++++++ public/react/src/common/reactQuill/index.scss | 32 ++++ public/react/src/common/reactQuill/lib.js | 13 ++ .../src/common/reactQuill/useDeepEqualMemo.js | 27 +++ .../src/common/reactQuill/useMountQuill.js | 148 ++++++++++++++++ .../react/src/common/reactQuill/useQuill.js | 60 +++++++ .../src/common/reactQuill/useQuillOnChange.js | 33 ++++ .../common/reactQuill/useQuillPlaceholder.js | 22 +++ .../common/reactQuill/useQuillValueSync.js | 31 ++++ .../src/modules/developer/DeveloperHome.js | 21 ++- .../components/controlSetting/index.js | 6 +- .../components/controlSetting/index.scss | 7 +- .../developer/components/execResult/index.js | 14 +- .../developer/components/initTabCtx/index.js | 7 +- .../components/initTabCtx/index.scss | 3 +- .../components/monacoSetting/index.js | 3 +- .../components/myMonacoEditor/index.js | 57 ++++-- .../components/myMonacoEditor/index.scss | 33 ++-- .../modules/developer/newOrEditTask/index.js | 102 ++++++----- .../developer/newOrEditTask/index.scss | 16 +- .../leftpane/editorTab/AddTestDemo.js | 24 ++- .../newOrEditTask/leftpane/editorTab/index.js | 53 +++--- .../leftpane/editorTab/index.scss | 5 + .../developer/newOrEditTask/leftpane/index.js | 22 --- .../newOrEditTask/leftpane/prevTab/index.js | 77 +++----- .../newOrEditTask/rightpane/index.scss | 2 +- .../modules/developer/split_pane_resizer.scss | 6 +- .../modules/developer/studentStudy/index.js | 56 ++++-- .../modules/developer/studentStudy/index.scss | 2 +- .../studentStudy/leftpane/comment/index.js | 13 +- .../studentStudy/leftpane/comment/index.scss | 8 + .../developer/studentStudy/leftpane/index.js | 63 ++----- .../studentStudy/leftpane/index.scss | 7 + .../leftpane/taskDescription/index.js | 18 +- .../developer/studentStudy/rightpane/index.js | 27 ++- public/react/src/redux/actions/actionTypes.js | 5 +- public/react/src/redux/actions/ojForUser.js | 45 ++++- public/react/src/redux/actions/ojForm.js | 20 ++- .../src/redux/reducers/ojForUserReducer.js | 24 ++- .../react/src/redux/reducers/ojFormReducer.js | 4 +- public/react/src/services/ojService.js | 15 +- 55 files changed, 1849 insertions(+), 296 deletions(-) create mode 100644 public/react/src/common/components/comment/CommentForm.js create mode 100644 public/react/src/common/components/comment/CommentIcon.js create mode 100644 public/react/src/common/components/comment/CommentItem.js create mode 100644 public/react/src/common/components/comment/CommentList.js create mode 100644 public/react/src/common/components/comment/index.js create mode 100644 public/react/src/common/components/comment/index.scss create mode 100644 public/react/src/common/quillForEditor/ImageBlot.js create mode 100644 public/react/src/common/quillForEditor/deepEqual.js create mode 100644 public/react/src/common/quillForEditor/index.js create mode 100644 public/react/src/common/reactQuill/ImageBlot.js create mode 100644 public/react/src/common/reactQuill/ReactQuill.js create mode 100644 public/react/src/common/reactQuill/deepEqual.js create mode 100644 public/react/src/common/reactQuill/flatten.js create mode 100644 public/react/src/common/reactQuill/index.js create mode 100644 public/react/src/common/reactQuill/index.scss create mode 100644 public/react/src/common/reactQuill/lib.js create mode 100644 public/react/src/common/reactQuill/useDeepEqualMemo.js create mode 100644 public/react/src/common/reactQuill/useMountQuill.js create mode 100644 public/react/src/common/reactQuill/useQuill.js create mode 100644 public/react/src/common/reactQuill/useQuillOnChange.js create mode 100644 public/react/src/common/reactQuill/useQuillPlaceholder.js create mode 100644 public/react/src/common/reactQuill/useQuillValueSync.js create mode 100644 public/react/src/modules/developer/studentStudy/leftpane/comment/index.scss diff --git a/public/react/package.json b/public/react/package.json index 66db5e6f8..144292feb 100644 --- a/public/react/package.json +++ b/public/react/package.json @@ -61,6 +61,7 @@ "prop-types": "^15.6.1", "qs": "^6.6.0", "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", diff --git a/public/react/src/common/components/comment/CommentForm.js b/public/react/src/common/components/comment/CommentForm.js new file mode 100644 index 000000000..73e36cff9 --- /dev/null +++ b/public/react/src/common/components/comment/CommentForm.js @@ -0,0 +1,116 @@ +/* + * @Description: 评论表单 + * @Author: tangjiang + * @Github: + * @Date: 2019-12-17 17:32:55 + * @LastEditors: tangjiang + * @LastEditTime: 2019-12-18 17:51:44 + */ +import React, { useState } from 'react'; +import { Form, Button, Input } from 'antd'; +import QuillForEditor from '../../quillForEditor'; +import { QuillDeltaToHtmlConverter } from 'quill-delta-to-html' +const FormItem = Form.Item; + +function CommentForm (props) { + + const { + commentCtxChagne, + onCancel, + onSubmit, + form + } = props; + + const { getFieldDecorator } = form; + const [ctx, setCtx] = useState(''); + + const options = [ + ['bold', 'italic', 'underline'], + [{header: [1,2,3,false]}], + ['blockquote', 'code-block'], + ['link', 'image'], + ['formula'] + ]; + // const { form: { getFieldDecorator } } = props; + const [showQuill, setShowQuill] = useState(false); + // 点击输入框 + const handleInputClick = () => { + setShowQuill(true); + } + // 取消 + const handleCancle = () => { + setShowQuill(false); + onCancel && onCancel(); + } + + // 编辑器内容变化时 + const handleContentChange = (content) => { + setCtx(content); + try { + const _html = new QuillDeltaToHtmlConverter(content.ops, {}).convert(); + // props.form.setFieldsValue({'comment': _html.replace(/<\/?[^>]*>/g, '')}); + props.form.setFieldsValue({'comment': _html}); + } catch (error) { + console.log(error); + } + } + // 发送 + const handleSubmit = (e) => { + e.preventDefault(); + props.form.validateFields((err, values) => { + if (!err) { + setShowQuill(false); + const content = ctx; + props.form.setFieldsValue({'comment': ''}); + setCtx(''); + console.log(content); + onSubmit && onSubmit(content); + } + }); + } + return ( + <Form> + <FormItem> + { + getFieldDecorator('comment', { + rules: [ + { required: true, message: '评论内容不能为空'} + ], + })( + <Input + onClick={handleInputClick} + placeholder="说点儿什么~" + style={{ + height: showQuill ? '0px' : '40px', + overflow: showQuill ? 'hidden' : 'auto', + opacity: showQuill ? 0 : 1, + transition: 'all .3s' + }} + /> + ) + } + + <QuillForEditor + imgAttrs={{width: '60px', height: '30px'}} + wrapStyle={{ + height: showQuill ? 'auto' : '0px', + opacity: showQuill ? 1 : 0, + overflow: showQuill ? 'none' : 'hidden', + transition: 'all 0.3s' + }} + style={{ height: '150px', overflowY: 'auto' }} + placeholder="说点儿什么~" + options={options} + value={ctx} + onContentChange={handleContentChange} + /> + </FormItem> + <FormItem style={{ textAlign: 'right' }}> + <Button onClick={handleCancle}>取消</Button> + <Button onClick={handleSubmit} type="primary" style={{ marginLeft: '10px'}}>发送</Button> + </FormItem> + </Form> + ); +} + +export default Form.create()(CommentForm); diff --git a/public/react/src/common/components/comment/CommentIcon.js b/public/react/src/common/components/comment/CommentIcon.js new file mode 100644 index 000000000..5440e2579 --- /dev/null +++ b/public/react/src/common/components/comment/CommentIcon.js @@ -0,0 +1,32 @@ +/* + * @Description: + * @Author: tangjiang + * @Github: + * @Date: 2019-12-18 10:49:46 + * @LastEditors: tangjiang + * @LastEditTime: 2019-12-18 11:39:23 + */ +import './index.scss'; +import React from 'react'; +import { Icon } from 'antd'; +function CommentIcon ({ + type, // 图标类型 + count, // 评论数 + iconClick, + ...props +}) { + + // 点击图标 + const handleSpanClick = () => { + iconClick && iconClick(); + } + + return ( + <span className={`comment_icon_count ${props.className}`} onClick={ handleSpanClick }> + <Icon className="comment_icon" type={type} /> + <span className="comment_count">{ count }</span> + </span> + ) +} + +export default CommentIcon; diff --git a/public/react/src/common/components/comment/CommentItem.js b/public/react/src/common/components/comment/CommentItem.js new file mode 100644 index 000000000..19da645f5 --- /dev/null +++ b/public/react/src/common/components/comment/CommentItem.js @@ -0,0 +1,165 @@ +/* + * @Description: 评论单列 + * @Author: tangjiang + * @Github: + * @Date: 2019-12-17 17:35:17 + * @LastEditors: tangjiang + * @LastEditTime: 2019-12-19 18:02:28 + */ +import './index.scss'; +import React, { useState } from 'react'; +import CommentIcon from './CommentIcon'; +import { getImageUrl, CNotificationHOC } from 'educoder' +import { Icon } from 'antd'; +import moment from 'moment'; +// import QuillForEditor from '../../quillForEditor'; +import CommentForm from './CommentForm'; + +// import {ModalConfirm} from '../ModalConfirm'; +function CommentItem ({ + options, + confirm +}) { + // 显示评论输入框 + const [showQuill, setShowQuill] = useState(false); + // 加载更多评论内容 + const [showMore, setShowMore] = useState(false); + // 箭头方向 + const [arrow, setArrow] = useState(false); + // 删除评论 + const deleteComment = () => { + console.log('删除评论...'); + confirm({ + title: '提示', + content: (<p>确定要删除该条回复吗?</p>), + onOk () { + console.log('点击了删除'); + } + }); + // ModalConfirm('提示', (<p>确定要删除该条回复吗?</p>), () => { + // console.log('点击了删除'); + // }); + } + + // 评论头像 + const commentAvatar = (url) => ( + <img className="item-flex flex-image" src='https://b-ssl.duitang.com/uploads/item/201511/13/20151113110434_kyReJ.jpeg' alt=""/> + ); + + // 评论信息 + const commentInfo = () => ( + <p className="item-header"> + <span className="item-name">用户名</span> + <span className="item-time">{moment(new Date(), 'YYYYMMDD HHmmss').fromNow()}</span> + <span className="item-close"><Icon type="close" onClick={deleteComment}/></span> + </p> + ); + + // 评论内容 + const commentCtx = (ctx) => ( + <p className="item-ctx"> + 这是评论内容这是评论内容这是评论内容这是评论内容这是评论内容这是评论内容这是评论内容这是评论内容这是评论内容这是评论内容 + </p> + ); + + // 加载更多 + const handleOnLoadMore = () => { + if (!arrow) { + // 展开所有 + } else { + // 收起 + } + setArrow(!arrow); + }; + + // 评论追加内容 + const commentAppend = () => { + + return ( + <ul className="comment_item_append_list"> + <li className="comment_item_area"> + {commentAvatar()} + <div className="item-flex item-desc"> + {commentInfo()} + {commentCtx()} + </div> + </li> + <li className="comment_item_area"> + {commentAvatar()} + <div className="item-flex item-desc"> + {commentInfo()} + {commentCtx()} + </div> + </li> + <li className="comment_item_area"> + {commentAvatar()} + <div className="item-flex item-desc"> + {commentInfo()} + {commentCtx()} + </div> + </li> + + <li className="comment_item_loadmore" onClick={handleOnLoadMore}> + <p className="loadmore-txt">展开其余23条评论</p> + <p className="loadmore-icon"> + <Icon type={!arrow ? 'down' : 'up'}/> + </p> + </li> + </ul> + ); + }; + // 点击图标 + const handleIconClick = () => {} + + // 点击评论icon + const handleClickMessage = () => { + setShowQuill(true); + } + + // 点击取消 + const handleClickCancel = () => { + setShowQuill(false); + } + + // 点击保存 + const handleClickSubmit = (content) => { + // 保存并关闭 + setShowQuill(false); + console.log('获取保存内容', content); + } + + return ( + <li className="comment_item_area"> + {commentAvatar()} + <div className="item-flex item-desc"> + {commentInfo()} + {commentCtx()} + + {commentAppend()} + + <div className="comment_icon_area"> + <CommentIcon className='comment-icon-margin' type="eye" count="100" iconClick={handleIconClick}/> + {/* 回复 */} + <CommentIcon + className='comment-icon-margin' + type="message" count="100" + iconClick={handleClickMessage} + /> + {/* 点赞 */} + <CommentIcon/> + </div> + + <div + style={{ display: showQuill ? 'block' : 'none'}} + className="comment_item_quill"> + <CommentForm + onCancel={handleClickCancel} + onSubmit={handleClickSubmit} + /> + </div> + </div> + </li> + ); +} + +export default CNotificationHOC() (CommentItem); diff --git a/public/react/src/common/components/comment/CommentList.js b/public/react/src/common/components/comment/CommentList.js new file mode 100644 index 000000000..9d8cde87b --- /dev/null +++ b/public/react/src/common/components/comment/CommentList.js @@ -0,0 +1,20 @@ +/* + * @Description: 评论列表页 + * @Author: tangjiang + * @Github: + * @Date: 2019-12-17 17:34:00 + * @LastEditors: tangjiang + * @LastEditTime: 2019-12-18 11:48:09 + */ +import './index.scss'; +import React from 'react'; +import CommentItem from './CommentItem'; +function CommentList ({}) { + return ( + <ul className="comment_list_wrapper"> + <CommentItem /> + </ul> + ); +} + +export default CommentList; diff --git a/public/react/src/common/components/comment/index.js b/public/react/src/common/components/comment/index.js new file mode 100644 index 000000000..f0ecf3309 --- /dev/null +++ b/public/react/src/common/components/comment/index.js @@ -0,0 +1,22 @@ +/* + * @Description: 评论组件 + * @Author: tangjiang + * @Github: + * @Date: 2019-12-17 17:31:33 + * @LastEditors: tangjiang + * @LastEditTime: 2019-12-18 11:47:39 + */ +import React from 'react'; +import CommentForm from './CommentForm'; +import CommentList from './CommentList'; +function Comment (props) { + + return ( + <React.Fragment> + <CommentForm /> + <CommentList /> + </React.Fragment> + ); +} + +export default Comment; diff --git a/public/react/src/common/components/comment/index.scss b/public/react/src/common/components/comment/index.scss new file mode 100644 index 000000000..816e6da6c --- /dev/null +++ b/public/react/src/common/components/comment/index.scss @@ -0,0 +1,111 @@ +$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; + + .comment_item_area{ + display: flex; + padding: 20px 0; + box-sizing: border-box; + border-bottom: 1px solid $bdColor; + .flex-image{ + width: 48px; + height: 48px; + border-radius: 50%; + } + .item-desc{ + flex: 1; + margin-left: $ml; + } + .item-header{ + font-size: $fz14; + line-height: $lh14; + color: #333; + .item-time{ + font-size: $fz12; + line-height: $lh14; + margin-left: $ml; + } + .item-close{ + float: right; + cursor: pointer; + } + } + .item-ctx{ + line-height: $lh22; + font-size: $fz12; + color: #333; + margin-top: 10px; + } + .comment_icon_area{ + display: flex; + justify-content: flex-end; + margin-top: 10px; + + .comment-icon-margin{ + margin-left: 30px; + } + } + + .comment_item_quill{ + margin-top: 20px; + } + } + .comment_icon_count{ + cursor: pointer; + font-size: 12px; + line-height: 1.5; + + .comment_icon{ + color: #333; + } + .comment_count{ + color: #999999; + margin-left: 10px; + transition: color .3s; + } + + &:hover{ + .comment_icon, + .comment_count{ + color: #5091FF; + } + } + } + .comment_item_append_list{ + position: relative; + background-color: $bgColor; + border-radius: 5px; + padding: 0 15px 10px; + margin: 15px 0; + &::before { + position: absolute; + left: 15px; + bottom: 100%; + height: 0; + width: 0; + content: ''; + // border: 5px solid transparent; + border: 10px solid transparent; + border-bottom-color: $bgColor; + } + + .comment_item_loadmore{ + padding-top: 10px; + cursor: pointer; + .loadmore-txt, + .loadmore-icon{ + color: #999; + text-align: center; + font-size: $fz12; + } + } + } +} \ No newline at end of file diff --git a/public/react/src/common/quillForEditor/ImageBlot.js b/public/react/src/common/quillForEditor/ImageBlot.js new file mode 100644 index 000000000..091bd2c1f --- /dev/null +++ b/public/react/src/common/quillForEditor/ImageBlot.js @@ -0,0 +1,54 @@ +/* + * @Description: 重写图片 + * @Author: tangjiang + * @Github: + * @Date: 2019-12-16 15:50:45 + * @LastEditors: tangjiang + * @LastEditTime: 2019-12-17 16:44:48 + */ +import Quill from "quill"; + +const BlockEmbed = Quill.import('blots/block/embed'); + +export default class ImageBlot extends BlockEmbed { + + static create(value) { + + const node = super.create(); + + node.setAttribute('alt', value.alt); + node.setAttribute('src', value.url); + + if (value.width) { + node.setAttribute('width', value.width); + } + if (value.height) { + node.setAttribute('height', value.height); + } + // 宽度和高度都不存在时, + if (!value.width && !value.height) { + node.setAttribute('display', 'block'); + node.setAttribute('width', '100%'); + } + // 给图片添加点击事件 + node.onclick = () => { + value.onClick && value.onClick(value.url); + } + return node; + } + + static value (node) { + + return { + alt: node.getAttribute('alt'), + url: node.getAttribute('src'), + onclick: node.onclick, + // width: node.width, + // height: node.height, + display: node.getAttribute('display') + }; + } +} + +ImageBlot.blotName = 'image'; +ImageBlot.tagName = 'img'; \ No newline at end of file diff --git a/public/react/src/common/quillForEditor/deepEqual.js b/public/react/src/common/quillForEditor/deepEqual.js new file mode 100644 index 000000000..6f2b276bf --- /dev/null +++ b/public/react/src/common/quillForEditor/deepEqual.js @@ -0,0 +1,47 @@ +function deepEqual (prev, current) { + if (prev === current) { // 基本类型比较,值,类型都相同 或者同为 null or undefined + return true; + } + + if ((!prev && current) + || (prev && !current) + || (!prev && !current) + ) { + return false; + } + + if (Array.isArray(prev)) { + if (!Array.isArray(current)) return false; + if (prev.length !== current.length) return false; + + for (let i = 0; i < prev.length; i++) { + if (!deepEqual(current[i], prev[i])) { + return false; + } + } + return true; + } + + if (typeof current === 'object') { + if (typeof prev !== 'object') return false; + const prevKeys = Object.keys(prev); + const curKeys = Object.keys(current); + + if (prevKeys.length !== curKeys.length) return false; + + prevKeys.sort(); + curKeys.sort(); + + for (let i = 0; i < prevKeys.length; i++) { + if (prevKeys[i] !== curKeys[i]) return false; + const key = prevKeys[i]; + if (!deepEqual(prev[key], current[key])) return false; + } + + return true; + } + + return false; +} + +export default deepEqual; diff --git a/public/react/src/common/quillForEditor/index.js b/public/react/src/common/quillForEditor/index.js new file mode 100644 index 000000000..6e6c01886 --- /dev/null +++ b/public/react/src/common/quillForEditor/index.js @@ -0,0 +1,166 @@ +/* + * @Description: quill 编辑器 + * @Author: tangjiang + * @Github: + * @Date: 2019-12-18 08:49:30 + * @LastEditors: tangjiang + * @LastEditTime: 2019-12-19 16:58:50 + */ +import 'quill/dist/quill.core.css'; // 核心样式 +import 'quill/dist/quill.snow.css'; // 有工具栏 +import 'quill/dist/quill.bubble.css'; // 无工具栏 +import 'katex/dist/katex.min.css'; // katex 表达式样式 +import React, { useState, useRef, useEffect } from 'react'; +import Quill from 'quill'; +import katex from 'katex'; +import deepEqual from './deepEqual.js' +import { fetchUploadImage } from '../../services/ojService.js'; +import { getImageUrl } from 'educoder' +import ImageBlot from './ImageBlot'; + +window.Quill = Quill; +window.katex = katex; +Quill.register(ImageBlot); + +function QuillForEditor ({ + placeholder, + readOnly, + options, + value, + imgAttrs = {}, // 指定图片的宽高 + style = {}, + wrapStyle = {}, + showUploadImage, + onContentChange +}) { + // toolbar 默认值 + const defaultConfig = [ + ['bold', 'italic', 'underline'], + [{align: []}, {list: 'ordered'}, {list: 'bullet'}], // 列表 + [{script: 'sub'}, {script: 'super'}], + [{ 'color': [] }, { 'background': [] }], + [{header: [1,2,3,4,5,false]}], + ['blockquote', 'code-block'], + ['link', 'image', 'video'], + ['formula'], + ['clean'] + ]; + + const editorRef = useRef(null); + // quill 实例 + const [quill, setQuill] = useState(null); + const [selection, setSelection] = useState(null); + + // 文本内容变化时 + const handleOnChange = content => { + // console.log('编辑器内容====》》》》', content); + onContentChange && onContentChange(content); + }; + + const renderOptions = options || defaultConfig; + // quill 配置信息 + const quillOption = { + modules: { + toolbar: renderOptions + }, + readOnly, + placeholder, + theme: readOnly ? 'bubble' : 'snow' + }; + + + useEffect(() => { + const _quill = new Quill(editorRef.current, quillOption); + setQuill(_quill); + + // 处理图片上传功能 + _quill.getModule('toolbar').addHandler('image', (e) => { + const input = document.createElement('input'); + input.setAttribute('type', 'file'); + input.setAttribute('accept', 'image/*'); + input.click(); + + input.onchange = async (e) => { + const file = input.files[0]; // 获取文件信息 + const formData = new FormData(); + formData.append('file', file); + + const range = _quill.getSelection(true); + let fileUrl = ''; // 保存上传成功后图片的url + // 上传文件 + const result = await fetchUploadImage(formData); + // 获取上传图片的url + if (result.data && result.data.id) { + fileUrl = getImageUrl(`api/attachments/${result.data.id}`); + } + // 根据id获取文件路径 + const { width, height } = imgAttrs; + // console.log('上传图片的url:', fileUrl); + if (fileUrl) { + _quill.insertEmbed(range.index, 'image', { + url: fileUrl, + alt: '图片信息', + onClick: showUploadImage, + width, + height + }); + } + } + }); + }, []); + + // 设置值 + useEffect(() => { + if (!quill) return + const previous = quill.getContents() + const current = value + + if (!deepEqual(previous, current)) { + setSelection(quill.getSelection()) + if (typeof value === 'string') { + quill.clipboard.dangerouslyPasteHTML(value, 'api') + } else { + quill.setContents(value) + } + } + }, [quill, value, setQuill]); + + // 清除选择区域 + useEffect(() => { + if (quill && selection) { + quill.setSelection(selection) + setSelection(null) + } + }, [quill, selection, setSelection]); + + // 设置placeholder值 + useEffect(() => { + if (!quill || !quill.root) return; + quill.root.dataset.placeholder = placeholder; + }, [quill, placeholder]); + + // 处理内容变化 + useEffect(() => { + if (!quill) return; + if (typeof handleOnChange !== 'function') return; + let handler; + quill.on( + 'text-change', + (handler = () => { + handleOnChange(quill.getContents()); // getContents: 检索编辑器内容 + }) + ); + return () => { + quill.off('text-change', handler); + } + }, [quill, handleOnChange]); + + // 返回结果 + return ( + <div className='quill_editor_for_react_area' style={wrapStyle}> + <div ref={editorRef} style={style}></div> + </div> + ); +} + +export default QuillForEditor; diff --git a/public/react/src/common/reactQuill/ImageBlot.js b/public/react/src/common/reactQuill/ImageBlot.js new file mode 100644 index 000000000..091bd2c1f --- /dev/null +++ b/public/react/src/common/reactQuill/ImageBlot.js @@ -0,0 +1,54 @@ +/* + * @Description: 重写图片 + * @Author: tangjiang + * @Github: + * @Date: 2019-12-16 15:50:45 + * @LastEditors: tangjiang + * @LastEditTime: 2019-12-17 16:44:48 + */ +import Quill from "quill"; + +const BlockEmbed = Quill.import('blots/block/embed'); + +export default class ImageBlot extends BlockEmbed { + + static create(value) { + + const node = super.create(); + + node.setAttribute('alt', value.alt); + node.setAttribute('src', value.url); + + if (value.width) { + node.setAttribute('width', value.width); + } + if (value.height) { + node.setAttribute('height', value.height); + } + // 宽度和高度都不存在时, + if (!value.width && !value.height) { + node.setAttribute('display', 'block'); + node.setAttribute('width', '100%'); + } + // 给图片添加点击事件 + node.onclick = () => { + value.onClick && value.onClick(value.url); + } + return node; + } + + static value (node) { + + return { + alt: node.getAttribute('alt'), + url: node.getAttribute('src'), + onclick: node.onclick, + // width: node.width, + // height: node.height, + display: node.getAttribute('display') + }; + } +} + +ImageBlot.blotName = 'image'; +ImageBlot.tagName = 'img'; \ No newline at end of file diff --git a/public/react/src/common/reactQuill/ReactQuill.js b/public/react/src/common/reactQuill/ReactQuill.js new file mode 100644 index 000000000..1b4209409 --- /dev/null +++ b/public/react/src/common/reactQuill/ReactQuill.js @@ -0,0 +1,45 @@ +/* + * @Description: + * @Author: tangjiang + * @Github: + * @Date: 2019-12-09 09:09:42 + * @LastEditors: tangjiang + * @LastEditTime: 2019-12-18 08:46:20 + */ +import 'quill/dist/quill.core.css'; // 核心样式 +import 'quill/dist/quill.snow.css'; // 有工具栏 +import 'quill/dist/quill.bubble.css'; // 无工具栏 +import 'katex/dist/katex.min.css'; // katex 表达式样式 +import React, { useState, useReducer, useEffect } from 'react'; +import useQuill from './useQuill'; + +function ReactQuill ({ + disallowColors, // 不可见时颜色 + placeholder, // 提示信息 + uploadImage, // 图片上传 + onChange, // 内容变化时 + options, // 配置信息 + value, // 显示的内容 + style, + showUploadImage // 显示上传图片 +}) { + + const [element, setElement] = useState(); // quill 渲染节点 + + useQuill({ + disallowColors, + placeholder, + uploadImage, + onChange, + options, + value, + showUploadImage, + element + }); + + return ( + <div className='react_quill_area' ref={setElement} style={style}/> + ); +} + +export default ReactQuill; diff --git a/public/react/src/common/reactQuill/deepEqual.js b/public/react/src/common/reactQuill/deepEqual.js new file mode 100644 index 000000000..6f2b276bf --- /dev/null +++ b/public/react/src/common/reactQuill/deepEqual.js @@ -0,0 +1,47 @@ +function deepEqual (prev, current) { + if (prev === current) { // 基本类型比较,值,类型都相同 或者同为 null or undefined + return true; + } + + if ((!prev && current) + || (prev && !current) + || (!prev && !current) + ) { + return false; + } + + if (Array.isArray(prev)) { + if (!Array.isArray(current)) return false; + if (prev.length !== current.length) return false; + + for (let i = 0; i < prev.length; i++) { + if (!deepEqual(current[i], prev[i])) { + return false; + } + } + return true; + } + + if (typeof current === 'object') { + if (typeof prev !== 'object') return false; + const prevKeys = Object.keys(prev); + const curKeys = Object.keys(current); + + if (prevKeys.length !== curKeys.length) return false; + + prevKeys.sort(); + curKeys.sort(); + + for (let i = 0; i < prevKeys.length; i++) { + if (prevKeys[i] !== curKeys[i]) return false; + const key = prevKeys[i]; + if (!deepEqual(prev[key], current[key])) return false; + } + + return true; + } + + return false; +} + +export default deepEqual; diff --git a/public/react/src/common/reactQuill/flatten.js b/public/react/src/common/reactQuill/flatten.js new file mode 100644 index 000000000..237cb543f --- /dev/null +++ b/public/react/src/common/reactQuill/flatten.js @@ -0,0 +1,26 @@ +/* + * @Description: 将多维数组转变成一维数组 + * @Author: tangjiang + * @Github: + * @Date: 2019-12-09 09:35:01 + * @LastEditors: tangjiang + * @LastEditTime: 2019-12-16 11:36:22 + */ +function flatten (array) { + return flatten.rec(array, []); +} + +flatten.rec = function flatten (array, result) { + + for (let item of array) { + if (Array.isArray(item)) { + flatten(item, result); + } else { + result.push(item); + } + } + + return result; +} + +export default flatten; diff --git a/public/react/src/common/reactQuill/index.js b/public/react/src/common/reactQuill/index.js new file mode 100644 index 000000000..56a1a8d1f --- /dev/null +++ b/public/react/src/common/reactQuill/index.js @@ -0,0 +1,108 @@ +/* + * @Description: 入口文件 + * @Author: tangjiang + * @Github: + * @Date: 2019-12-17 10:41:48 + * @LastEditors: tangjiang + * @LastEditTime: 2019-12-17 20:34:40 + */ +import React, { useState, useCallback, useEffect } from 'react'; +import ReactQuill from './lib'; + +function Wrapper (props) { + // 默认工具栏配置项 + const toolbarConfig = [ + ['bold', 'italic', 'underline'], + [{align: []}, {list: 'ordered'}, {list: 'bullet'}], // 列表 + [{script: 'sub'}, {script: 'super'}], + [{header: [1,2,3,4,5,false]}], + ['blockquote', 'code-block'], + ['link', 'image', 'video'], + ['formula'], + ['clean'] + ]; + + const [placeholder] = useState(props.placeholder || 'placeholder'); + const [disableBold] = useState(false); + const [value, setValue] = useState(props.value || ''); + const [toolbar, setToolbar] = useState(toolbarConfig); + const [theme, setTheme] = useState(props.theme || 'snow'); + const [readOnly] = useState(props.readOnly || false); + + const { + onContentChagne, // 当编辑器内容变化时调用该函数 + showUploadImage, // 显示上传图片, 返回url,主要用于点击图片放大 + } = props; + + // 配置信息 + const options = { + modules: { + toolbar: toolbar, + clipboard: { + matchVisual: false + } + }, + readOnly: readOnly, + theme: theme + } + // 配置信息 + useEffect (() => { + if (props.options) { + setToolbar(props.options); + } + setTheme(props.theme || 'snow'); + setValue(props.value); + }, [props]); + + // 当内容变化时 + const handleOnChange = useCallback( + contents => { + if (disableBold) { + setValue({ + ops: contents.ops.map(x => { + x = {...x}; + if (x && x.attributes && x.attributes.bold) { + x.attributes = { ...x.attributes }; + delete x.attributes.bold; + if (!Object.keys(x.attributes).length) { + delete x.attributes; + } + } + return x; + }) + }); + } else { + setValue(contents); + } + onContentChagne && onContentChagne(contents); + }, [disableBold] + ); + + // 图片上传 + const handleUploadImage = (files) => { + console.log('选择的图片信息', files); + } + + // 显示图片 + const handleShowUploadImage = (url) => { + // console.log('上传的图片url:', url); + showUploadImage && showUploadImage(url); + } + + return ( + <React.Fragment> + <ReactQuill + value={value} + style={props.style} + onChange={handleOnChange} + placeholder={`${placeholder}`} + options={options} + uploadImage={handleUploadImage} + showUploadImage={(url) => handleShowUploadImage(url)} + /> + </React.Fragment> + ); +} + +export default Wrapper; +// ReactDOM.render(<Wrapper />, document.querySelector('#root')); diff --git a/public/react/src/common/reactQuill/index.scss b/public/react/src/common/reactQuill/index.scss new file mode 100644 index 000000000..b6da52bf5 --- /dev/null +++ b/public/react/src/common/reactQuill/index.scss @@ -0,0 +1,32 @@ +#quill-toolbar{ + .quill-btn{ + vertical-align: middle; + } + .quill_image{ + display: inline-block; + position: relative; + vertical-align: middle; + width: 28px; + height: 24px; + overflow: hidden; + .image_input{ + position: absolute; + left: 0; + right: 0; + top: 0; + bottom: 0; + opacity: 0; + } + .ql-image{ + position: relative; + left: 0; + top: 0; + } + } +} + +.react_quill_area{ + .ql-toolbar:not(:last-child) { + display: none; + } +} \ No newline at end of file diff --git a/public/react/src/common/reactQuill/lib.js b/public/react/src/common/reactQuill/lib.js new file mode 100644 index 000000000..430a95bb7 --- /dev/null +++ b/public/react/src/common/reactQuill/lib.js @@ -0,0 +1,13 @@ +/* + * @Description: 导出 ReactQuill + * @Author: tangjiang + * @Github: + * @Date: 2019-12-09 09:08:24 + * @LastEditors: tangjiang + * @LastEditTime: 2019-12-16 11:37:13 + */ +import ReactQuill from './ReactQuill'; +import useQuill from './useQuill'; + +export default ReactQuill; +export { useQuill }; diff --git a/public/react/src/common/reactQuill/useDeepEqualMemo.js b/public/react/src/common/reactQuill/useDeepEqualMemo.js new file mode 100644 index 000000000..948e21781 --- /dev/null +++ b/public/react/src/common/reactQuill/useDeepEqualMemo.js @@ -0,0 +1,27 @@ +/* + * @Description: + * @Author: tangjiang + * @Github: + * @Date: 2019-12-12 19:48:55 + * @LastEditors: tangjiang + * @LastEditTime: 2019-12-16 11:38:16 + */ +import { useState, useEffect } from 'react'; +import deepEqual from './deepEqual'; + +function useDeepEqual (input) { + + const [value, setValue] = useState(input); + + useEffect(() => { + + if (!deepEqual(input, value)) { + setValue(input) + } + + }, [input, value]); + + return value; +} + +export default useDeepEqual; diff --git a/public/react/src/common/reactQuill/useMountQuill.js b/public/react/src/common/reactQuill/useMountQuill.js new file mode 100644 index 000000000..c2313c480 --- /dev/null +++ b/public/react/src/common/reactQuill/useMountQuill.js @@ -0,0 +1,148 @@ +/* + * @Description: 创建 reactQuill实例 + * @Author: tangjiang + * @Github: + * @Date: 2019-12-09 09:31:42 + * @LastEditors: tangjiang + * @LastEditTime: 2019-12-17 20:42:05 + */ +import Quill from 'quill'; // 导入quill +import { useState, useEffect, useMemo } from 'react'; +import flatten from './flatten.js'; +import useDeepEqualMemo from './useDeepEqualMemo'; +import Katex from 'katex'; +import ImageBlot from './ImageBlot'; +import { fetchUploadImage } from '../../services/ojService.js'; +import { getImageUrl } from 'educoder' +window.katex = Katex; + +Quill.register(ImageBlot); + +function useMountQuill ({ + element, + options: passedOptions, + uploadImage, + showUploadImage, + imgAttrs = {} // 指定图片的宽高属性 +}) { + + // 是否引入 katex + const [katexLoaded, setKatexLoaded] = useState(Boolean(window.katex)) + const [quill, setQuill] = useState(null); + + const options = useDeepEqualMemo(passedOptions); + console.log('use mount quill: ', passedOptions); + + // 判断options中是否包含公式 + const requireKatex = useMemo(() => { + return flatten(options.modules.toolbar).includes('formula'); + }, [options]); + + // 加载katex + useEffect(() => { + if (!requireKatex) return; + if (katexLoaded) return; + + const interval = setInterval(() => { + if (window.katex) { + setKatexLoaded(true); + clearInterval(interval); + } + }); + + return () => { // 定义回调清除定时器 + clearInterval(interval); + } + + }, [ + setKatexLoaded, + katexLoaded, + requireKatex + ]); + + // 加载 quill + useEffect(() => { + if (!element) return; + if (requireKatex && !katexLoaded) { + element.innerHTML = ` + <div style="color: #ddd"> + Loading Katex... + </div> + ` + } + // 清空内容 + element.innerHTML = ''; + console.log(element); + // 创建 quill 节点 + const quillNode = document.createElement('div'); + element.appendChild(quillNode); // 将quill节点追回到 element 元素中 + + const quill = new Quill(element, options); + setQuill(quill); + // 加载上传图片功能 + if (typeof uploadImage === 'function') { + quill.getModule('toolbar').addHandler('image', (e) => { + // 创建type类型输入框加载本地图片 + const input = document.createElement('input'); + input.setAttribute('type', 'file'); + input.setAttribute('accept', 'image/*'); + input.click(); + + input.onchange = async (e) => { + const file = input.files[0]; // 获取文件信息 + const formData = new FormData(); + formData.append('file', file); + + // const reader = new FileReader(); + // reader.readAsDataURL(file); + // console.log('文件信息===>>', reader); + // reader.onload = function (e) { + // debugger; + // console.log('文件信息===>>', e.target.result); + // const image = new Image(); + // image.src = e.target.result; + + // image.onload = function () { + // // file.width = + // console.log(image.width, image.height); + // } + // } + + const range = quill.getSelection(true); + let fileUrl = ''; // 保存上传成功后图片的url + // 上传文件 + const result = await fetchUploadImage(formData); + // 获取上传图片的url + if (result.data && result.data.id) { + fileUrl = getImageUrl(`api/attachments/${result.data.id}`); + } + // 根据id获取文件路径 + const { width, height } = imgAttrs; + // console.log('上传图片的url:', fileUrl); + if (fileUrl) { + quill.insertEmbed(range.index, 'image', { + url: fileUrl, + alt: '', + onClick: showUploadImage, + width, + height + }); + } + } + }); + } + + return () => { + element.innerHTML = ''; + } + }, [ + element, + options, + requireKatex, + katexLoaded, + ]); + + return quill; +} + +export default useMountQuill; diff --git a/public/react/src/common/reactQuill/useQuill.js b/public/react/src/common/reactQuill/useQuill.js new file mode 100644 index 000000000..b959dbc52 --- /dev/null +++ b/public/react/src/common/reactQuill/useQuill.js @@ -0,0 +1,60 @@ +/* + * @Description: + * @Author: tangjiang + * @Github: + * @Date: 2019-12-09 09:09:50 + * @LastEditors: tangjiang + * @LastEditTime: 2019-12-17 15:46:50 + */ +import useQuillPlaceholder from './useQuillPlaceholder'; +import useQuillValueSync from './useQuillValueSync'; +import useQuillOnChange from './useQuillOnChange'; +import useMountQuill from './useMountQuill'; +import { useEffect } from 'react'; + +function useQuill ({ + disallowColors, + placeholder, + uploadImage, + onChange, + options, + value, + element, + showUploadImage +}) { + + // 获取 quill 实例 + const quill = useMountQuill({ + element, + options, + uploadImage, + showUploadImage + }); + + useEffect(() => { + if (disallowColors && quill) { + quill.clipboard.addMatcher(Node.ELEMENT_NODE, (node, delta) => { + delta.ops = delta.ops.map(op => { + if (op.attributes && op.attributes.color) { + const { color, ...attributes } = op.attributes; + return { + ...op, + attributes + } + } + return op; + }); + return delta; + }); + } + }, [ + disallowColors, + quill + ]); + + useQuillPlaceholder(quill, placeholder); + useQuillValueSync(quill, value); + useQuillOnChange(quill, onChange); +} + +export default useQuill; diff --git a/public/react/src/common/reactQuill/useQuillOnChange.js b/public/react/src/common/reactQuill/useQuillOnChange.js new file mode 100644 index 000000000..45333a4e1 --- /dev/null +++ b/public/react/src/common/reactQuill/useQuillOnChange.js @@ -0,0 +1,33 @@ +/* + * @Description: + * @Author: tangjiang + * @Github: + * @Date: 2019-12-12 19:49:11 + * @LastEditors: tangjiang + * @LastEditTime: 2019-12-16 11:39:27 + */ +import { useEffect } from 'react'; + +function useQuillOnChange (quill, onChange) { + + useEffect(() => { + + if (!quill) return; + if (typeof onChange !== 'function') return; + + let handler; + + quill.on( + 'text-change', + (handler = () => { + onChange(quill.getContents()); // getContents: 检索编辑器内容 + }) + ); + + return () => { + quill.off('text-change', handler); + } + }, [quill, onChange]); +} + +export default useQuillOnChange; diff --git a/public/react/src/common/reactQuill/useQuillPlaceholder.js b/public/react/src/common/reactQuill/useQuillPlaceholder.js new file mode 100644 index 000000000..ccc341568 --- /dev/null +++ b/public/react/src/common/reactQuill/useQuillPlaceholder.js @@ -0,0 +1,22 @@ +/* + * @Description: + * @Author: tangjiang + * @Github: + * @Date: 2019-12-09 09:28:34 + * @LastEditors: tangjiang + * @LastEditTime: 2019-12-16 11:39:48 + */ +import { useEffect } from 'react' + +function useQuillPlaceholder ( + quill, + placeholder +) { + + useEffect(() => { + if (!quill || !quill.root) return; + quill.root.dataset.placeholder = placeholder; + }, [quill, placeholder]); +} + +export default useQuillPlaceholder; diff --git a/public/react/src/common/reactQuill/useQuillValueSync.js b/public/react/src/common/reactQuill/useQuillValueSync.js new file mode 100644 index 000000000..696d88949 --- /dev/null +++ b/public/react/src/common/reactQuill/useQuillValueSync.js @@ -0,0 +1,31 @@ +import { useEffect, useState } from 'react' +import deepEqual from './deepEqual.js' + +function useQuillValueSync(quill, value) { + const [selection, setSelection] = useState(null) + + useEffect(() => { + if (!quill) return + + const previous = quill.getContents() + const current = value + + if (!deepEqual(previous, current)) { + setSelection(quill.getSelection()) + if (typeof value === 'string') { + quill.clipboard.dangerouslyPasteHTML(value, 'api') + } else { + quill.setContents(value) + } + } + }, [quill, value, setSelection]) + + useEffect(() => { + if (quill && selection) { + quill.setSelection(selection) + setSelection(null) + } + }, [quill, selection, setSelection]) +} + +export default useQuillValueSync diff --git a/public/react/src/modules/developer/DeveloperHome.js b/public/react/src/modules/developer/DeveloperHome.js index 5f787659e..73a5c37a1 100644 --- a/public/react/src/modules/developer/DeveloperHome.js +++ b/public/react/src/modules/developer/DeveloperHome.js @@ -16,7 +16,7 @@ import MultipTags from './components/multiptags'; // import { Link } from 'react-router-dom'; import CONST from '../../constants'; import { withRouter } from 'react-router'; -import { toStore } from 'educoder'; +import { toStore, CNotificationHOC } from 'educoder'; // import MyIcon from '../../common/components/MyIcon'; const {tagBackground, diffText} = CONST; @@ -249,17 +249,26 @@ class DeveloperHome extends React.PureComponent { // 删除 handleClickDelete = (record) => { const { deleteItem } = this.props; - Modal.confirm({ - title: '删除', + this.props.confirm({ + title: '提示', content: `确定要删除${record.name}吗?`, - okText: '确定', - cancelText: '取消', onOk () { // 调用删除接口 console.log(record.identifier); deleteItem(record.identifier); } }); + // Modal.confirm({ + // title: '删除', + // content: `确定要删除${record.name}吗?`, + // okText: '确定', + // cancelText: '取消', + // onOk () { + // // 调用删除接口 + // console.log(record.identifier); + // deleteItem(record.identifier); + // } + // }); } // table条件变化时 handleTableChange = (pagination, filters, sorter) => { @@ -562,5 +571,5 @@ const mapDispatchToProps = (dispatch) => ({ export default withRouter(connect( mapStateToProps, mapDispatchToProps -)(DeveloperHome)); +)(CNotificationHOC() (DeveloperHome))); // export default DeveloperHome; diff --git a/public/react/src/modules/developer/components/controlSetting/index.js b/public/react/src/modules/developer/components/controlSetting/index.js index 587e1bee9..b5c9222ef 100644 --- a/public/react/src/modules/developer/components/controlSetting/index.js +++ b/public/react/src/modules/developer/components/controlSetting/index.js @@ -4,7 +4,7 @@ * @Github: * @Date: 2019-11-27 16:02:36 * @LastEditors: tangjiang - * @LastEditTime: 2019-12-13 17:32:33 + * @LastEditTime: 2019-12-19 10:47:44 */ import './index.scss'; import React, { useState, useRef } from 'react'; @@ -30,7 +30,7 @@ const ControlSetting = (props) => { // debuggerCode, // startDebuggerCode, // 外部存入 onDebuggerCode, - updateCode, + // updateCode, onSubmitForm } = props; const [defaultActiveKey, setDefaultActiveKey] = useState('1'); // 当前选中的tab @@ -84,7 +84,7 @@ const ControlSetting = (props) => { <Tabs className={classNames} activeKey={defaultActiveKey} - tabBarStyle={{ backgroundColor: 'rgba(48,48,48,1)', color: '#fff' }} + tabBarStyle={{ backgroundColor: 'rgba(18,28,36,1)', color: '#fff' }} onChange={handleTabChange} > <TabPane tab={'自定义测试用例'} key={'1'} style={{ height: '280px', overflowY: 'auto' }}> diff --git a/public/react/src/modules/developer/components/controlSetting/index.scss b/public/react/src/modules/developer/components/controlSetting/index.scss index 97838ce5c..31beda8a5 100644 --- a/public/react/src/modules/developer/components/controlSetting/index.scss +++ b/public/react/src/modules/developer/components/controlSetting/index.scss @@ -2,7 +2,8 @@ position: absolute; bottom: 0; width: 100%; - background:rgba(30,30,30,1); + // background: red; + // background:rgba(30,30,30,1); // height: 56px; .control_tab{ position: absolute; @@ -52,8 +53,8 @@ height: 56px; padding-right: 30px; padding-left: 10px; - // background: #000; - background:rgba(48,48,48,1); + background: rgba(18,28,36,1); + // background:rgba(48,48,48,1); } .setting_drawer{ diff --git a/public/react/src/modules/developer/components/execResult/index.js b/public/react/src/modules/developer/components/execResult/index.js index 32bbbee91..6f9341b9a 100644 --- a/public/react/src/modules/developer/components/execResult/index.js +++ b/public/react/src/modules/developer/components/execResult/index.js @@ -4,7 +4,7 @@ * @Github: * @Date: 2019-11-28 08:44:54 * @LastEditors: tangjiang - * @LastEditTime: 2019-12-10 09:24:02 + * @LastEditTime: 2019-12-19 10:44:16 */ import './index.scss'; import React, { useState, useEffect } from 'react'; @@ -38,6 +38,15 @@ function ExecResult (props) { </span> </div> ); + + const renderError = () => ( + <div className={'excute_result_area excute_flex_center'}> + <span className={'loaded_ctx'}> + <span>未知异常</span> + </span> + </div> + ) + const renderFinish = () => { const { error_line, @@ -60,6 +69,7 @@ function ExecResult (props) { ) } + // console.log('执行结果====》》》》', status); const excuteCtx = (state) => { if (state === 0) { return ( @@ -118,6 +128,8 @@ function ExecResult (props) { setRenderCtx(() => (readerLoaded)); } else if ('finish' === excuteState) { setRenderCtx(() => (renderFinish)); + } else if ('error' === excuteState) { + setRenderCtx(() => (renderError)) } }, [excuteState]); diff --git a/public/react/src/modules/developer/components/initTabCtx/index.js b/public/react/src/modules/developer/components/initTabCtx/index.js index 3834a3e11..3e707daa1 100644 --- a/public/react/src/modules/developer/components/initTabCtx/index.js +++ b/public/react/src/modules/developer/components/initTabCtx/index.js @@ -4,7 +4,7 @@ * @Github: * @Date: 2019-11-27 19:46:14 * @LastEditors: tangjiang - * @LastEditTime: 2019-12-13 17:38:42 + * @LastEditTime: 2019-12-19 10:47:05 */ import './index.scss'; import React, { useState, useEffect, useRef, useImperativeHandle, forwardRef } from 'react'; @@ -26,6 +26,7 @@ function InitTabCtx (props, ref) { const { inputValue, onDebuggerCode } = props; + console.log('default value', inputValue); useImperativeHandle(ref, () => ({ handleTestCodeFormSubmit: (cb) => { // console.log('父组件调用我啦~~~~~~~~~'); @@ -33,6 +34,10 @@ function InitTabCtx (props, ref) { } })); + useEffect(() => { + console.log('初始值: ========', props); + }, [props]); + // 渲染文本提示信息 const renderText = () => (<span className={'ctx_default'}>请在这里添加测试用例,点击“调试代码”时将从这里读取输入来测试你的代码...</span>); // 渲染表单信息 diff --git a/public/react/src/modules/developer/components/initTabCtx/index.scss b/public/react/src/modules/developer/components/initTabCtx/index.scss index 449db1d2a..5427aa374 100644 --- a/public/react/src/modules/developer/components/initTabCtx/index.scss +++ b/public/react/src/modules/developer/components/initTabCtx/index.scss @@ -49,7 +49,8 @@ } .input_textarea_style{ - background:rgba(30,30,30,1) !important; + // background:rgba(30,30,30,1) !important; + background:rgba(7,15,25,1) !important; color: #fff; border-color: transparent; outline: none; diff --git a/public/react/src/modules/developer/components/monacoSetting/index.js b/public/react/src/modules/developer/components/monacoSetting/index.js index a101819e0..c1215f9af 100644 --- a/public/react/src/modules/developer/components/monacoSetting/index.js +++ b/public/react/src/modules/developer/components/monacoSetting/index.js @@ -4,10 +4,11 @@ * @Github: * @Date: 2019-11-25 17:50:33 * @LastEditors: tangjiang - * @LastEditTime: 2019-12-06 16:51:48 + * @LastEditTime: 2019-12-19 15:26:46 */ import React, { useState } from 'react'; import { fromStore, toStore } from 'educoder'; +import { Icon } from 'antd'; // import { Select } from 'antd'; // const { Option } = Select; const SettingDrawer = (props) => { diff --git a/public/react/src/modules/developer/components/myMonacoEditor/index.js b/public/react/src/modules/developer/components/myMonacoEditor/index.js index 60f54ee0a..df3c2b5e3 100644 --- a/public/react/src/modules/developer/components/myMonacoEditor/index.js +++ b/public/react/src/modules/developer/components/myMonacoEditor/index.js @@ -4,12 +4,12 @@ * @Github: * @Date: 2019-11-27 15:02:52 * @LastEditors: tangjiang - * @LastEditTime: 2019-12-13 16:16:56 + * @LastEditTime: 2019-12-19 17:52:31 */ import './index.scss'; import React, { useState, useRef, useEffect } from 'react'; -import { Drawer, Modal } from 'antd'; -import { fromStore } from 'educoder'; +import { Drawer, Modal, Icon, Badge } from 'antd'; +import { fromStore, CNotificationHOC } from 'educoder'; import { connect } from 'react-redux'; import MonacoEditor from '@monaco-editor/react'; import SettingDrawer from '../../components/monacoSetting'; @@ -19,16 +19,25 @@ import MyIcon from '../../../../common/components/MyIcon'; // import actions from '../../../../redux/actions'; const { fontSetting, opacitySetting } = CONST; +const maps = { + 'c': 'main.c', + 'c++': 'main.cc', + 'java': 'main.java', + 'pythone': 'main.py' +}; function MyMonacoEditor (props, ref) { const { + notice, language, identifier, + hadCodeUpdate, showOrHideControl, // saveUserInputCode, onCodeChange, - onRestoreInitialCode + onRestoreInitialCode, + onUpdateNotice } = props; const [showDrawer, setShowDrawer] = useState(false); // 控制配置滑框 @@ -50,7 +59,7 @@ function MyMonacoEditor (props, ref) { }, [props]); useEffect(() => { - setHeight(showOrHideControl ? 'calc(100% - 382px)' : 'calc(100% - 56px)'); + setHeight(showOrHideControl ? 'calc(100% - 378px)' : 'calc(100% - 56px)'); }, [showOrHideControl]); // 控制侧边栏设置的显示 @@ -93,28 +102,51 @@ function MyMonacoEditor (props, ref) { // 恢复初始代码 const handleRestoreCode = () => { - Modal.confirm({ + props.confirm({ + title: '提示', content: '确定要恢复代码吗?', - okText: '确定', - cancelText: '取消', onOk () { onRestoreInitialCode && onRestoreInitialCode(); } }) + // Modal.confirm({ + // content: '确定要恢复代码吗?', + // okText: '确定', + // cancelText: '取消', + // onOk () { + // onRestoreInitialCode && onRestoreInitialCode(); + // } + // }) + } + + const handleUpdateNotice = () => { + if (props.notice) { + onUpdateNotice && onUpdateNotice(); + } } const renderRestore = identifier ? ( <MyIcon type="iconzaicizairu" /> ) : ''; + + // lex_has_save ${hadCodeUpdate} ? : '' + const _classnames = hadCodeUpdate ? `flex_strict flex_has_save` : 'flex_strict'; return ( <React.Fragment> <div className={"monaco_editor_area"}> <div className="code_title"> {/* 未保存时 ? '学员初始代码文件' : main.x */} - <span className='flex_strict' style={{ color: '#fff'}}>{identifier ? '' : '学员初始代码文件'}</span> - <span className='flex_strict'>{identifier ? '已保存' : ''}</span> + <span className='flex_strict' style={{ color: '#ddd'}}>{identifier ? language ? maps[language.toLowerCase()] : '' : '学员初始代码文件'}</span> + <span className={_classnames}>{identifier ? '已保存' : ''}</span> + <Badge + className="flex_normal" + style={{ color: '#666'}} + dot={notice} + onClick={handleUpdateNotice} + > + <Icon type="bell" /> + </Badge> <span onClick={handleRestoreCode} className="flex_normal">{renderRestore}</span> - {/* <Icon className={'code-icon'} type="setting" onClick={handleShowDrawer}/> */} <MyIcon className='code-icon' type="iconshezhi" onClick={handleShowDrawer}/> </div> <MonacoEditor @@ -131,7 +163,6 @@ function MyMonacoEditor (props, ref) { <Drawer className={'setting_drawer'} placement="right" - closable={false} onClose={handleDrawerClose} visible={showDrawer} > @@ -161,4 +192,4 @@ const mapDispatchToProps = (dispatch) => ({ export default connect( mapStateToProps, mapDispatchToProps -)(MyMonacoEditor); +)(CNotificationHOC() (MyMonacoEditor)); diff --git a/public/react/src/modules/developer/components/myMonacoEditor/index.scss b/public/react/src/modules/developer/components/myMonacoEditor/index.scss index 7a7c4f030..61689b51e 100644 --- a/public/react/src/modules/developer/components/myMonacoEditor/index.scss +++ b/public/react/src/modules/developer/components/myMonacoEditor/index.scss @@ -1,19 +1,17 @@ .monaco_editor_area{ height: 100%; - background-color: rgba(30,30,30,1); + background-color: rgba(7,15,25,1); .code_title{ display: flex; align-items: center; - // justify-content: space-between; - // background: #000; - // background: #333333; - background-color: rgba(48,48,48,1); + background-color: rgba(18,28,36,1); color: #fff; height: 56px; padding: 0 30px; .flex_strict{ flex: 1; } + .flex_normal{ color: #E51C24; cursor: pointer; @@ -25,21 +23,21 @@ .flex_strict, .flex_normal, .code-icon{ - color: #888; + color: #666; } } } .setting_drawer{ - // .ant-drawer-body{ - // // height: calc(100vh - 120px); - // // overflow-y: auto; - // } + .ant-drawer-close{ + color: #ffffff; + } .ant-drawer-content{ top: 120px; bottom: 56px; height: calc(100vh - 176px); - background: #333333; + // background: #333333; + background: rgba(7,15,25,1); color: #fff; .setting_h2{ color: #fff; @@ -57,4 +55,17 @@ color: #fff; } } +} + +.flex_has_save{ + // animation: blink 3s line 3; + animation-name: blink; + animation-duration: .4s; + animation-iteration-count: 3; +} + +@keyframes blink{ + 50% { + color: #fff; + } } \ No newline at end of file diff --git a/public/react/src/modules/developer/newOrEditTask/index.js b/public/react/src/modules/developer/newOrEditTask/index.js index bc905fdf7..1c451c669 100644 --- a/public/react/src/modules/developer/newOrEditTask/index.js +++ b/public/react/src/modules/developer/newOrEditTask/index.js @@ -13,11 +13,11 @@ import { Button, Modal } from 'antd'; import LeftPane from './leftpane'; import RightPane from './rightpane'; import { withRouter } from 'react-router'; -import { toStore } from 'educoder'; +import { toStore, CNotificationHOC } from 'educoder'; import UserInfo from '../components/userInfo'; // import RightPane from './rightpane/index'; import actions from '../../../redux/actions'; -import {ModalConfirm} from '../../../common/components/ModalConfirm'; +// import {ModalConfirm} from '../../../common/components/ModalConfirm'; const NewOrEditTask = (props) => { const { @@ -69,10 +69,13 @@ const NewOrEditTask = (props) => { // 模拟挑战 const imitationChallenge = () => { + // 调用 start 接口, 成功后跳转到模拟页面 + startProgramQuestion(identifier, props); } // 开始挑战 const startChallenge = () => { - // 调用 start 接口, 成功后跳转到模拟页面 + // 调用 start 接口, 成功后跳转到开启实战 + // TODO startProgramQuestion(identifier, props); } @@ -82,27 +85,38 @@ const NewOrEditTask = (props) => { props.clearOJFormStore(); // 清空描述信息 toStore('oj_description', ''); - setInterval(function () { - props.history.push('/problems'); - }, 500); + props.history.push('/problems'); } // 发布 const handleClickPublish = () => { - ModalConfirm('提示', (<p>发布后即可应用到自己管理的课堂<br /> 是否确认发布?</p>), () => { - changePublishLoadingStatus(true); - handlePublish(props, 'publish'); + // ModalConfirm('提示', (<p>发布后即可应用到自己管理的课堂<br /> 是否确认发布?</p>), () => { + // changePublishLoadingStatus(true); + // handlePublish(props, 'publish'); + // }); + props.confirm({ + title: '提示', + content: (<p>发布后即可应用到自己管理的课堂<br /> 是否确认发布?</p>), + onOk () { + changePublishLoadingStatus(true); + handlePublish(props, 'publish'); + } }); - - } // 撤销发布 const handleClickCancelPublish = () => { - ModalConfirm('提示', (<p>是否确认撤销发布?</p>), () => { - changePublishLoadingStatus(true); - handleCancelPublish(props, identifier); + // ModalConfirm('提示', (<p>是否确认撤销发布?</p>), () => { + // changePublishLoadingStatus(true); + // handleCancelPublish(props, identifier); + // }); + props.confirm({ + title: '提示', + content: ((<p>是否确认撤销发布?</p>)), + onOk () { + changePublishLoadingStatus(true); + handleCancelPublish(props, identifier); + } }); - } // 取消保存/取消按钮 @@ -125,6 +139,7 @@ const NewOrEditTask = (props) => { const renderPubOrFight = () => { const pubButton = isPublish ? (<Button + style={{ background: 'rgba(102,102,102,1)', border: 'none' }} type="primary" loading={publishLoading} onClick={handleClickCancelPublish} @@ -141,39 +156,40 @@ const NewOrEditTask = (props) => { <Button type="primary" onClick={imitationChallenge}>模拟挑战</Button> ); - // 更新 - // const updateBtn = isPublish - // ? '' - // : ( - // <Button - // type="primary" - // loading={submitLoading} - // onClick={handleSubmitForm} - // >更新</Button> - // ); - return ( - <React.Fragment> - <Button - type="primary" - loading={submitLoading} - onClick={handleSubmitForm} - >更新</Button> - {pubButton} - {challengeBtn} - </React.Fragment> - ) + if (isPublish) { + return ( + <React.Fragment> + {pubButton} + <Button + type="primary" + loading={submitLoading} + onClick={handleSubmitForm} + >保存</Button> + {challengeBtn} + </React.Fragment> + ); + } else { + return ( + <React.Fragment> + <Button + type="primary" + loading={submitLoading} + onClick={handleSubmitForm} + >保存</Button> + {pubButton} + {challengeBtn} + </React.Fragment> + ); + } + } // 渲染退出 const renderQuit = () => { return identifier ? ( <Button type="link" - style={{ - position: 'absolute', - right: '10px', - top: '15px', - color: '#5091FF' - }} + icon='poweroff' + className='quite_btn' onClick={handleClickCancel} >退出</Button> ) : '' @@ -255,4 +271,4 @@ const mapDispatchToProps = (dispatch) => ({ export default withRouter(connect( mapStateToProps, mapDispatchToProps -)(NewOrEditTask)); +)(CNotificationHOC() (NewOrEditTask))); diff --git a/public/react/src/modules/developer/newOrEditTask/index.scss b/public/react/src/modules/developer/newOrEditTask/index.scss index ba0ed8503..ad668fcc8 100644 --- a/public/react/src/modules/developer/newOrEditTask/index.scss +++ b/public/react/src/modules/developer/newOrEditTask/index.scss @@ -10,9 +10,23 @@ align-items: center; justify-content: center; height: 56px; - background: #333333; + // background: #333333; + background: rgba(18,28,36,1); > button{ margin-right: 20px; } } +.quite_btn{ + position: absolute; + right: 10px; + top: 15px; + margin-left: 30px; + color: #888888; + transition: all .3s; + cursor: pointer; + &:hover{ + color: #5091FF; + } +} + diff --git a/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/AddTestDemo.js b/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/AddTestDemo.js index 4c4131fa9..8e7aa70fc 100644 --- a/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/AddTestDemo.js +++ b/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/AddTestDemo.js @@ -4,13 +4,14 @@ * @Github: * @Date: 2019-11-21 09:19:38 * @LastEditors: tangjiang - * @LastEditTime: 2019-12-13 11:58:46 + * @LastEditTime: 2019-12-19 17:54:28 */ import './index.scss'; import React, { useState } from 'react'; -import { Collapse, Icon, Input, Form, Button, Modal } from 'antd'; +import { Collapse, Icon, Input, Form, Button } from 'antd'; import { connect } from 'react-redux'; import actions from '../../../../../redux/actions'; +import { CNotificationHOC} from 'educoder'; const { Panel } = Collapse; const { TextArea } = Input; const FormItem = Form.Item; @@ -31,15 +32,22 @@ const AddTestDemo = (props) => { // console.log('点击的删除按钮') e.preventDefault(); e.stopPropagation(); - Modal.confirm({ - title: '删除', + props.confirm({ + title: '提示', content: '确定要删除当前测试用例吗?', - okText: '确定', - cancelText: '取消', onOk() { onDeleteTest(testCase); } - }) + }); + // Modal.confirm({ + // title: '删除', + // content: '确定要删除当前测试用例吗?', + // okText: '确定', + // cancelText: '取消', + // onOk() { + // onDeleteTest(testCase); + // } + // }) } // 输入框值改变时 @@ -189,4 +197,4 @@ const mapDispatchToProps = (dispatch) => ({ export default connect( mapStateToProps, mapDispatchToProps -)(Form.create()(AddTestDemo)); +)(Form.create()(CNotificationHOC()(AddTestDemo))); diff --git a/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/index.js b/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/index.js index 762d1d3ba..da31754bd 100644 --- a/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/index.js +++ b/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/index.js @@ -4,21 +4,20 @@ * @Github: * @Date: 2019-11-20 10:35:40 * @LastEditors: tangjiang - * @LastEditTime: 2019-12-13 11:39:52 + * @LastEditTime: 2019-12-19 17:23:10 */ -import 'quill/dist/quill.core.css'; -import 'quill/dist/quill.bubble.css'; -import 'quill/dist/quill.snow.css'; import './index.scss'; // import 'katex/dist/katex.css'; import React from 'react'; import { Form, Input, Select, InputNumber, Button } from 'antd'; import { connect } from 'react-redux'; import AddTestDemo from './AddTestDemo'; -import QuillEditor from '../../../quillEditor'; +// import QuillEditor from '../../../quillEditor'; import actions from '../../../../../redux/actions'; import CONST from '../../../../../constants'; -import { fromStore, toStore } from 'educoder'; // 保存和读取store值 +import { toStore } from 'educoder'; // 保存和读取store值 +// import Wrapper from '../../../../../common/reactQuill'; +import QuillForEditor from '../../../../../common/quillForEditor'; const scrollIntoView = require('scroll-into-view'); const {jcLabel} = CONST; const FormItem = Form.Item; @@ -26,9 +25,9 @@ const { Option } = Select; const maps = { language: [ { title: 'C', key: 'C' }, - // { title: 'C++', key: 'C++' }, - // { title: 'Python', key: 'Python' }, - // { title: 'Java', key: 'Java' } + { title: 'C++', key: 'C++' }, + { title: 'Python', key: 'Python' }, + { title: 'Java', key: 'Java' } ], difficult: [ { title: '简单', key: '1' }, @@ -146,9 +145,6 @@ class EditTab extends React.Component { testCasesValidate, openTestCodeIndex = [] } = this.props; - // console.log('当前位置: ', position); - // console.log('OJForm: ', ojForm); - // console.log('当前位置: ', testCases); // 表单label const myLabel = (name, subTitle) => { if (subTitle) { @@ -185,7 +181,6 @@ class EditTab extends React.Component { }; const renderTestCase = () => { return this.props.testCases.map((item, i) => { - console.log(111); return <AddTestDemo key={`${i}`} isOpen={openTestCodeIndex.includes(i)} @@ -222,17 +217,25 @@ class EditTab extends React.Component { // TODO 点击新增时,需要滚到到最底部 this.scrollToBottom(); } + + // 描述信息变化时 + const handleContentChange = (content) => { + console.log('描述信息为: ', content); + // 保存获取的描述信息至redux中 + this.handleChangeDescription(content); + } // 编辑器配置信息 const quillConfig = [ [{ header: [1, 2, 3, 4, 5, 6, false] }], ['bold', 'italic', 'underline', 'strike'], // 切换按钮 ['blockquote', 'code-block'], // 代码块 - [{ 'list': 'ordered' }, { 'list': 'bullet' }], // 列表 + [{align: []}, { 'list': 'ordered' }, { 'list': 'bullet' }], // 列表 [{ 'script': 'sub'}, { 'script': 'super' }], [{ 'color': [] }, { 'background': [] }], // 字体颜色与背景色 - ['formula', 'image', 'video'], // 数学公式、图片、视频 + ['image', 'formula'], // 数学公式、图片、视频 ['clean'], // 清除格式 ]; + return ( <div className={'editor_area'} id="textCase"> <Form className={'editor_form'}> @@ -267,7 +270,7 @@ class EditTab extends React.Component { help={ojFormValidate.timeLimit.errMsg} colon={ false } > - <InputNumber value={ojForm.timeLimit} min={0} style={{ width: '100%' }} onChange={this.handleTimeLimitChange}/> + <InputNumber value={ojForm.timeLimit} min={0} max={5} style={{ width: '100%' }} onChange={this.handleTimeLimitChange}/> </FormItem> <FormItem @@ -305,13 +308,16 @@ class EditTab extends React.Component { help={ojFormValidate.description.errMsg} colon={ false } > - <QuillEditor - style={{ height: '300px' }} - placeholder="请输入描述信息" - onEditorChange={this.handleChangeDescription} - htmlCtx={ojForm.description || fromStore('oj_description')} - options={quillConfig} - /> + <div style={{ marginTop: '15px'}}> + <QuillForEditor + style={{ height: '200px', 'overflowY': 'auto' }} + placeholder="init content" + onContentChange={handleContentChange} + options={quillConfig} + value={ojForm.description} + /> + </div> + </FormItem> {/* <FormItem @@ -325,6 +331,7 @@ class EditTab extends React.Component { {getOptions('openOrNot')} </Select> </FormItem> */} + </Form> {/* 添加测试用例 */} diff --git a/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/index.scss b/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/index.scss index f8fa3bd71..17f3eae34 100644 --- a/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/index.scss +++ b/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/index.scss @@ -49,6 +49,11 @@ .test_demo_ctx, .editor_form{ margin: 0 30px; + + .ant-form-explain{ + margin-top: 5px; + margin-left: -10px; + } } .test_demo_title{ display: flex; diff --git a/public/react/src/modules/developer/newOrEditTask/leftpane/index.js b/public/react/src/modules/developer/newOrEditTask/leftpane/index.js index 8b10413a9..781b82699 100644 --- a/public/react/src/modules/developer/newOrEditTask/leftpane/index.js +++ b/public/react/src/modules/developer/newOrEditTask/leftpane/index.js @@ -34,28 +34,6 @@ function LeftPane (props) { const [defaultActiveKey, setDefaultActiveKey] = useState('editor'); - // const tabArrs = [ - // { title: '编辑', key: 'editor', content: (<EditorTab />) }, - // { title: '预览', key: 'prev', content: (<PrevTab />) }, - // // { title: '提交记录', key: 'commit', content: (<CommitTab />) }, - // ]; - - // const tabs = tabArrs.map((tab) => { - // const Comp = tab.content; - // return ( - // <TabPane tab={tab.title} key={tab.key}> - // { Comp } - // </TabPane> - // ) - // }); - - // tab切换时 - // const handleTabChange = (key) => { - // setDefaultActiveKey(key); - // } - - // 执行表单提交函数 - const renderComp = useMemo(() => { return Comp[defaultActiveKey]; }, [defaultActiveKey]); diff --git a/public/react/src/modules/developer/newOrEditTask/leftpane/prevTab/index.js b/public/react/src/modules/developer/newOrEditTask/leftpane/prevTab/index.js index c45628973..6b41d3489 100644 --- a/public/react/src/modules/developer/newOrEditTask/leftpane/prevTab/index.js +++ b/public/react/src/modules/developer/newOrEditTask/leftpane/prevTab/index.js @@ -4,74 +4,47 @@ * @Github: * @Date: 2019-11-24 10:09:55 * @LastEditors: tangjiang - * @LastEditTime: 2019-12-04 23:38:37 + * @LastEditTime: 2019-12-18 10:02:24 */ import './index.scss'; import React, { useEffect, useState, useRef } from 'react'; import { connect } from 'react-redux'; import {Empty} from 'antd'; -// import QuillEditor from '../../../quillEditor'; -const Quill = window.Quill; +// import Wrapper from '../../../../../common/reactQuill'; +import QuillForEditor from '../../../../../common/quillForEditor'; const PrevTab = (props) => { - const { - description - } = props; const prevRef = useRef(null); - const [desc, setDesc] = useState(''); - const [renderCtx, setRenderCtx] = useState(() => { - return function () { - return ''; - } - }); - - // 空内容 - const renderTxt = () => ( - <div className='no_result'> - <Empty /> - </div> - ); + // const [desc, setDesc] = useState(''); + const [renderCtx, setRenderCtx] = useState(() => ''); + // 渲染内容 - const renderQuill = () => ( - <div - id="quill_editor" - style = {{ height: '100%', width: '100%'}} - ref={prevRef}> - </div> - ); - useEffect(() => { - setDesc(description); - }, [description]); - - useEffect(() => { - if (description) { - setRenderCtx(() => renderQuill); - let count = 0; - let timer = setInterval(() => { - count++; - if (count >= 10 || prevRef.current) { - clearInterval(timer); - timer = null; - if (prevRef.current) { - const quillEditor = new Quill(prevRef.current, { - readOnly: true, - theme: 'bubble' - }); - quillEditor.container.firstChild.innerHTML = description; - } - } - }, 50); + if (props.description) { + setRenderCtx(() => ( + <div + id="quill_editor" + style = {{ height: '100%', width: '100%'}} + ref={prevRef}> + <QuillForEditor + readOnly={true} + value={props.description} + /> + </div> + )); } else { - setRenderCtx(() => renderTxt); + setRenderCtx(() => ( + <div className='no_result'> + <Empty /> + </div> + )); } - - }, [description]); + }, [props]); return ( <div className={`prev_area`}> - {renderCtx()} + {renderCtx} </div> ) diff --git a/public/react/src/modules/developer/newOrEditTask/rightpane/index.scss b/public/react/src/modules/developer/newOrEditTask/rightpane/index.scss index 48f5a7bb9..ea2f37c20 100644 --- a/public/react/src/modules/developer/newOrEditTask/rightpane/index.scss +++ b/public/react/src/modules/developer/newOrEditTask/rightpane/index.scss @@ -1,7 +1,7 @@ .right_pane_code_wrap{ position: relative; // justify-content: center; - background-color: #222; + // background-color: #222; height: 100%; // height: calc(100vh - 178px); .code-title, diff --git a/public/react/src/modules/developer/split_pane_resizer.scss b/public/react/src/modules/developer/split_pane_resizer.scss index 498370dd6..2898d966c 100644 --- a/public/react/src/modules/developer/split_pane_resizer.scss +++ b/public/react/src/modules/developer/split_pane_resizer.scss @@ -8,7 +8,8 @@ .record_detail_header{ height: 65px; // background:rgba(34,34,34,1); - background: #1E1E1E; + // background: #1E1E1E; + background: rgba(7,15,25,1); padding:0 30px; } @@ -123,7 +124,8 @@ .split-pane-area, .split-pane-left{ .ant-tabs-nav-wrap{ - padding: 0 30px; + // padding: 0 30px; + padding: 0 20px; } .ant-tabs-bar{ margin: 0; diff --git a/public/react/src/modules/developer/studentStudy/index.js b/public/react/src/modules/developer/studentStudy/index.js index e4b296a20..1db9f7f28 100644 --- a/public/react/src/modules/developer/studentStudy/index.js +++ b/public/react/src/modules/developer/studentStudy/index.js @@ -4,7 +4,7 @@ * @Github: * @Date: 2019-11-23 10:53:19 * @LastEditors: tangjiang - * @LastEditTime: 2019-12-13 17:19:15 + * @LastEditTime: 2019-12-19 17:51:19 */ import './index.scss'; import React, { useEffect, useState } from 'react'; @@ -15,10 +15,10 @@ import RightPane from './rightpane'; // import { Link } from 'react-router-dom'; // import { getImageUrl } from 'educoder' // import RightPane from '../newOrEditTask/rightpane'; -import { Icon, Modal } from 'antd'; +import { Icon } from 'antd'; import UserInfo from '../components/userInfo'; import actions from '../../../redux/actions'; -import { fromStore} from 'educoder'; +import { fromStore, CNotificationHOC} from 'educoder'; import { withRouter } from 'react-router'; function StudentStudy (props) { @@ -51,23 +51,39 @@ function StudentStudy (props) { const { hack = {} } = props; if (hack.modify_code && hasUpdate) { // 代码更改,提示是否需要更新代码 setHasUpdate(false); - Modal.confirm({ - title: '提示', - content: ( - <p> - 代码文件有更新啦 <br /> - 还未提交的代码,请自行保存 - </p> - ), - okText: '立即更新', - cancelText: '稍后再说', - onOk () { - restoreInitialCode(id, '更新成功'); - } - }); + handleUpdateNotice(); } }, [props, hasUpdate, setHasUpdate]); + const handleUpdateNotice = () => { + console.log(props); + props.confirm({ + title: '提示', + content: ( + <p> + 代码文件有更新啦 <br /> + 还未提交的代码,请自行保存 + </p> + ), + onOk () { + restoreInitialCode(id, '更新成功'); + } + }) + // Modal.confirm({ + // title: '提示', + // content: ( + // <p> + // 代码文件有更新啦 <br /> + // 还未提交的代码,请自行保存 + // </p> + // ), + // okText: '立即更新', + // cancelText: '稍后再说', + // onOk () { + // restoreInitialCode(id, '更新成功'); + // } + // }); + } const _hack_id = hack_identifier || fromStore('hack_identifier'); // 处理编辑 @@ -117,7 +133,9 @@ function StudentStudy (props) { <LeftPane /> </div> <SplitPane split="vertical" defaultSize="100%" allowResize={false}> - <RightPane /> + <RightPane + updateNotice={handleUpdateNotice} + /> <div /> </SplitPane> </SplitPane> @@ -151,6 +169,6 @@ const mapDispatchToProps = (dispatch) => ({ export default withRouter(connect( mapStateToProps, mapDispatchToProps -)(StudentStudy)); +)(CNotificationHOC()(StudentStudy))); diff --git a/public/react/src/modules/developer/studentStudy/index.scss b/public/react/src/modules/developer/studentStudy/index.scss index bbf66aebb..68835f2ce 100644 --- a/public/react/src/modules/developer/studentStudy/index.scss +++ b/public/react/src/modules/developer/studentStudy/index.scss @@ -5,6 +5,6 @@ .right_pane_code_wrap{ position: relative; - background-color: #222; + // background-color: #222; height: 100%; } diff --git a/public/react/src/modules/developer/studentStudy/leftpane/comment/index.js b/public/react/src/modules/developer/studentStudy/leftpane/comment/index.js index 329e8fba1..ca7160117 100644 --- a/public/react/src/modules/developer/studentStudy/leftpane/comment/index.js +++ b/public/react/src/modules/developer/studentStudy/leftpane/comment/index.js @@ -4,15 +4,18 @@ * @Github: * @Date: 2019-11-27 09:49:35 * @LastEditors: tangjiang - * @LastEditTime: 2019-11-27 09:52:53 + * @LastEditTime: 2019-12-17 17:46:05 */ +import './index.scss'; import React from 'react'; - -const Comment = (props) => { +import Comment from '../../../../../common/components/comment'; +const CommentTask = (props) => { return ( - <h2> Comment </h2> + <div className="task_comment_task"> + <Comment /> + </div> ) } -export default Comment; +export default CommentTask; diff --git a/public/react/src/modules/developer/studentStudy/leftpane/comment/index.scss b/public/react/src/modules/developer/studentStudy/leftpane/comment/index.scss new file mode 100644 index 000000000..ba9c132d9 --- /dev/null +++ b/public/react/src/modules/developer/studentStudy/leftpane/comment/index.scss @@ -0,0 +1,8 @@ +.task_comment_task{ + background: #fff; + padding: 20px 30px 0; + height: calc(100vh - 177px); + box-sizing: border-box; + overflow-y: auto; + border-bottom: 1px solid rgba(244,244,244,1); +} \ No newline at end of file diff --git a/public/react/src/modules/developer/studentStudy/leftpane/index.js b/public/react/src/modules/developer/studentStudy/leftpane/index.js index 69f49b9b1..347f4b4f8 100644 --- a/public/react/src/modules/developer/studentStudy/leftpane/index.js +++ b/public/react/src/modules/developer/studentStudy/leftpane/index.js @@ -4,11 +4,11 @@ * @Github: * @Date: 2019-11-23 11:33:41 * @LastEditors: tangjiang - * @LastEditTime: 2019-12-09 19:57:21 + * @LastEditTime: 2019-12-19 18:03:22 // */ import './index.scss'; import React, { useState, useEffect, useMemo } from 'react'; -import { Tabs, Divider } from 'antd'; +import { Divider } from 'antd'; import { connect } from 'react-redux'; import Comment from './comment'; import CommitRecord from './commitRecord'; @@ -19,17 +19,10 @@ import actions from '../../../../redux/actions'; const LeftPane = (props) => { - const { hack, userCodeTab, changeUserCodeTab } = props; + const { hack, userCodeTab } = props; const { pass_count, submit_count } = hack; - const [defaultActiveKey, setDefaultActiveKey] = useState('task'); + const [defaultActiveKey, setDefaultActiveKey] = useState('comment'); - console.log(pass_count, submit_count); - const tabArrs = [ - { title: '任务描述', key: 'task', content: (<TaskDescription />) }, - { title: '提交记录', key: 'record', content: (<CommitRecord />) }, - // { title: '评论', key: 'comment', content: (<Comment />) }, - ]; - const navItem = [ { title: '任务描述', @@ -38,38 +31,30 @@ const LeftPane = (props) => { { title: '提交记录', key: 'record' - } + }, + // { + // title: '评论', + // key: 'comment' + // } ]; const Comp = { task: (<TaskDescription />), - record: (<CommitRecord />) + record: (<CommitRecord />), + comment: (<Comment />) }; useEffect(() => { + console.log('====>>>>', userCodeTab); setDefaultActiveKey(userCodeTab); }, [userCodeTab]) - // const tabs = tabArrs.map((tab) => { - // const Comp = tab.content; - // return ( - // <TabPane tab={tab.title} key={tab.key}> - // { Comp } - // </TabPane> - // ) - // }); - - // // tab切换时 - // const handleTabChange = (key) => { - // // setDefaultActiveKey(key); - // changeUserCodeTab(key); - // } - const renderComp = useMemo(() => { return Comp[defaultActiveKey]; - }, [defaultActiveKey]); + }, [defaultActiveKey, setDefaultActiveKey]); const renderNavItem = navItem.map((item) => { + const _classes = item.key === defaultActiveKey ? 'add_editor_item active' : 'add_editor_item'; return ( <li @@ -99,21 +84,6 @@ const LeftPane = (props) => { return ( <React.Fragment> - {/* <Tabs className={'user_code_tab_area'} activeKey={defaultActiveKey} onChange={handleTabChange}> - { tabs } - </Tabs> - <div className={'number_area'}> - <div className="number_flex flex_count"> - <TextNumber text="通过次数" number={pass_count} position="vertical"/> - <Divider type="vertical" style={{ height: '20px', margin: '10px 20px' }}/> - <TextNumber text="提交次数" number={submit_count} position="vertical"/> - </div> - <div className="number_flex flex_info"> - <TextNumber text="message" number={4235} type="icon" onIconClick={handleClickMessage}/> - <TextNumber text="like" number={4235} type="icon" onIconClick={handleClickLike}/> - <TextNumber text="dislike" type="icon" onIconClick={handleClickDisLike}/> - </div> - </div> */} <ul className={'add_editor_list_area'}> { renderNavItem } </ul> @@ -126,11 +96,6 @@ const LeftPane = (props) => { <Divider type="vertical" style={{ height: '20px', margin: '10px 20px' }}/> <TextNumber text="提交次数" number={submit_count} position="vertical"/> </div> - {/* <div className="number_flex flex_info"> - <TextNumber text="message" number={4235} type="icon" onIconClick={handleClickMessage}/> - <TextNumber text="like" number={4235} type="icon" onIconClick={handleClickLike}/> - <TextNumber text="dislike" type="icon" onIconClick={handleClickDisLike}/> - </div> */} </div> </React.Fragment> ); diff --git a/public/react/src/modules/developer/studentStudy/leftpane/index.scss b/public/react/src/modules/developer/studentStudy/leftpane/index.scss index 9e6f019f6..1582c033f 100644 --- a/public/react/src/modules/developer/studentStudy/leftpane/index.scss +++ b/public/react/src/modules/developer/studentStudy/leftpane/index.scss @@ -13,6 +13,8 @@ bottom: 0px; height: 56px; width: 100%; + box-sizing: border-box; + border-top: 1px solid rgba(244,244,244,1); // background: pink; padding: 0 30px; // background-color: rgba(250,250,250,1); @@ -79,4 +81,9 @@ margin-right: 5px; } } +} + +.add_editor_list_area{ + box-sizing: border-box; + border-bottom: 1px solid rgba(244,244,244,1); } \ No newline at end of file diff --git a/public/react/src/modules/developer/studentStudy/leftpane/taskDescription/index.js b/public/react/src/modules/developer/studentStudy/leftpane/taskDescription/index.js index 28fe51765..981770b8c 100644 --- a/public/react/src/modules/developer/studentStudy/leftpane/taskDescription/index.js +++ b/public/react/src/modules/developer/studentStudy/leftpane/taskDescription/index.js @@ -4,14 +4,15 @@ * @Github: * @Date: 2019-11-27 09:49:30 * @LastEditors: tangjiang - * @LastEditTime: 2019-12-09 19:21:55 + * @LastEditTime: 2019-12-19 09:22:52 */ import '../index.scss'; import React from 'react'; import { Tag } from 'antd'; import { Link } from 'react-router-dom'; import { connect } from 'react-redux'; -import QuillEditor from '../../../quillEditor'; +import QuillForEditor from '../../../../../common/quillForEditor'; + import CONST from '../../../../../constants'; const {tagBackground, diffText} = CONST; @@ -36,22 +37,15 @@ const TaskDescription = (props) => { </p> <p className={'header_flex'}> <span className={'flex_label'}>出题者:</span> - <Link to="/" style={{ color: '#5091FF'}}>{username}</Link> + <Link to="/messages/innov/message_detail" target="_blank" style={{ color: '#5091FF'}}>{username}</Link> </p> </div> <div className="task_desc_area"> - <QuillEditor - htmlCtx={description} + <QuillForEditor readOnly={true} + value={description} /> </div> - {/* <QuillEditor - htmlCtx={description} - readOnly={true} - options={[]} - style={{ backgroundColor: 'gold' }} - /> */} - {/* <div dangerouslySetInnerHTML={{__html: description}}></div> */} </div> ) } diff --git a/public/react/src/modules/developer/studentStudy/rightpane/index.js b/public/react/src/modules/developer/studentStudy/rightpane/index.js index 669a8a693..5661ea32e 100644 --- a/public/react/src/modules/developer/studentStudy/rightpane/index.js +++ b/public/react/src/modules/developer/studentStudy/rightpane/index.js @@ -4,7 +4,7 @@ * @Github: * @Date: 2019-11-27 14:59:51 * @LastEditors: tangjiang - * @LastEditTime: 2019-12-13 16:50:40 + * @LastEditTime: 2019-12-19 15:06:49 */ import React, { useState, useEffect } from 'react'; import {connect} from 'react-redux'; @@ -20,8 +20,11 @@ const RightPane = (props) => { submitUserCode, input, hack, + notice, updateCode, + hadCodeUpdate, editor_code, + updateNotice, saveUserInputCode, restoreInitialCode, saveUserCodeForInterval @@ -48,7 +51,8 @@ const RightPane = (props) => { // 代码块内容变化时 const handleCodeChange = (code) => { // 保存用户提交的代码块 - console.log(code); + // console.log(code); + setEditorCode(code); if (!timer) { timer = setInterval(() => { clearInterval(timer); @@ -69,13 +73,21 @@ const RightPane = (props) => { restoreInitialCode(identifier, '恢复初始代码成功'); } + // 更新代码 + const handleUpdateNotice = () => { + updateNotice && updateNotice(); + }; + return ( <div className={'right_pane_code_wrap'}> <MyMonacoEditor + notice={notice} identifier={identifier} language={hack.language} code={editorCode} + hadCodeUpdate={hadCodeUpdate} onCodeChange={handleCodeChange} + onUpdateNotice={handleUpdateNotice} onRestoreInitialCode={handleRestoreInitialCode} /> <ControlSetting @@ -89,10 +101,19 @@ const RightPane = (props) => { const mapStateToProps = (state) => { - const {user_program_identifier, hack, userTestInput, editor_code} = state.ojForUserReducer; + const { + user_program_identifier, + hack, + userTestInput, + editor_code, + notice, + hadCodeUpdate + } = state.ojForUserReducer; // const { language, code } = hack; return { hack, + notice, + hadCodeUpdate, editor_code, input: userTestInput, submitInput: hack.input, diff --git a/public/react/src/redux/actions/actionTypes.js b/public/react/src/redux/actions/actionTypes.js index 0f33b435c..c872486e2 100644 --- a/public/react/src/redux/actions/actionTypes.js +++ b/public/react/src/redux/actions/actionTypes.js @@ -22,7 +22,8 @@ const types = { SAVE_OJ_FORM: 'SAVE_OJ_FORM', // 保存表单 ADD_TEST_CASE: 'ADD_TEST_CASE', // 添加测试用例 DELETE_TEST_CASE: 'DELETE_TEST_CASE', // 删除测试用例 - SAVE_TEST_CASE: '保存测试用例', // 保存测试用例 + SAVE_TEST_CASE: 'SAVE_TEST_CASE', // 保存测试用例 + SAVE_USE_TEST_CASE_VALUE: 'SAVE_USE_TEST_CASE_VALUE', // 用户自定义测试用例值 CLEAR_JSFORM_STORE: 'CLEAR_JSFORM_STORE', // 清空测试用例 SAVE_EDIT_OJ_FORM_AND_TEST_CASE: 'SAVE_EDIT_OJ_FORM_AND_TEST_CASE', // 保存根据id获取的表单及测试用例值 TEST_CODE_STATUS: 'TEST_CODE_STATUS', // 代码调试状态 @@ -50,6 +51,8 @@ const types = { SAVE_USER_INFO: 'SAVE_USER_INFO', // 只在用户信息 SAVE_HACK_IDENTIFIER: 'SAVE_HACK_IDENTIFIER', // 用户界面跑到编辑界面需要用的id值 SAVE_EDITOR_CODE: 'SAVE_EDITOR_CODE', // 保存详情页面中编辑时的代码 + SAVE_NOTICE_COUNT: 'SAVE_NOTICE_COUNT', // 保存代码块是否更新 + AUTO_UPDATE_CODE: 'AUTO_UPDATE_CODE', // 自动更新代码 } export default types; diff --git a/public/react/src/redux/actions/ojForUser.js b/public/react/src/redux/actions/ojForUser.js index 79e2045d6..9cb814d80 100644 --- a/public/react/src/redux/actions/ojForUser.js +++ b/public/react/src/redux/actions/ojForUser.js @@ -4,7 +4,7 @@ * @Github: * @Date: 2019-11-27 13:42:11 * @LastEditors: tangjiang - * @LastEditTime: 2019-12-13 16:49:42 + * @LastEditTime: 2019-12-19 15:11:56 */ import types from "./actionTypes"; import { Base64 } from 'js-base64'; @@ -82,6 +82,20 @@ export const getUserProgramDetail = (identifier, type) => { payload: data }); } + // 保存默认测试用例 + dispatch({ + type: types.SAVE_USE_TEST_CASE_VALUE, + payload: data.test_case || {} + }); + // 代码是否更新 + let _modify_code = false; + if (data.hack) { + _modify_code = data.hack.modify_code; + } + dispatch({ + type: types.SAVE_NOTICE_COUNT, + payload: _modify_code + }) // 保存用户登录信息 dispatch({ type: types.SAVE_USER_INFO, @@ -94,13 +108,29 @@ export const getUserProgramDetail = (identifier, type) => { export const saveUserCodeForInterval = (identifier, code) => { return (dispatch) => { + dispatch({ + type: types.AUTO_UPDATE_CODE, + payload: true + }); fetchUpdateCode(identifier, { code: Base64.encode(code) }).then(res => { if (res.data.status === 401) { return; }; + + setTimeout(() => { + dispatch({ + type: types.AUTO_UPDATE_CODE, + payload: false + }) + }, 1000); console.log('代码保存成功', res); + }).catch(() => { + dispatch({ + type: types.AUTO_UPDATE_CODE, + payload: false + }) }); } } @@ -259,7 +289,11 @@ export const debuggerCode = (identifier,value, type) => { }).catch(() => { dispatch({ type: types.TEST_CODE_STATUS, - payload: '' + payload: 'error' + }); + dispatch({ + type: types.LOADING_STATUS, + payload: false }); dispatch({ type: types.SUBMIT_LOADING_STATUS, @@ -400,6 +434,10 @@ export const restoreInitialCode = (identifier, msg) => { message: '提示', description: msg }); + dispatch({ + type: types.SAVE_NOTICE_COUNT, + payload: false + }); } }); } @@ -412,3 +450,6 @@ export const saveEditorCodeForDetail = (code) => { payload: code } } + +// 更新通知状态 + diff --git a/public/react/src/redux/actions/ojForm.js b/public/react/src/redux/actions/ojForm.js index 3eaac9023..740bad895 100644 --- a/public/react/src/redux/actions/ojForm.js +++ b/public/react/src/redux/actions/ojForm.js @@ -4,7 +4,7 @@ * @Github: * @Date: 2019-11-20 16:35:46 * @LastEditors: tangjiang - * @LastEditTime: 2019-12-13 16:56:22 + * @LastEditTime: 2019-12-19 17:20:48 */ import types from './actionTypes'; import CONST from '../../constants'; @@ -15,7 +15,7 @@ import { cancelPublicTask } from '../../services/ojService'; import { Base64 } from 'js-base64'; -import { message, notification, Modal } from 'antd'; +import { notification } from 'antd'; import { toStore } from 'educoder'; const { jcLabel } = CONST; // 表单字段映射 @@ -160,7 +160,7 @@ export const validateOjForm = (props, type) => { if (testCases.length === 0) { hasSuccess = false; notification['error']({ - message: '必填', + message: '提示', description: '测试用例必须输入!' }); } @@ -200,7 +200,7 @@ export const validateOjForm = (props, type) => { let paramsObj = {}; const hack = { // 编程题干 name, - description, + description: JSON.stringify(description), difficult, category, 'open_or_not': openOrNot, @@ -449,9 +449,13 @@ export const testCaseInputChange = (value, index) => { let validate = emptyValidate('input', value)['input']; if (!validate.errMsg) { // 唯一性校验 + let _errMsg = ''; const {testCases} = getState().ojFormReducer; const bool = testCases.some((item, i) => { if (i !== index) { + if (item['input'] === value) { + _errMsg=`与测试用例${index}的输入值重复了,请重新填写`; + } return item['input'] === value; } else { return false; @@ -460,7 +464,7 @@ export const testCaseInputChange = (value, index) => { if (bool) { validate = { validateStatus: 'error', - errMsg: '输入值必须唯一' + errMsg: _errMsg }; } } @@ -492,8 +496,12 @@ export const testCaseOutputChange = (value, index) => { if (!validate.errMsg) { // 唯一性校验 const {testCases} = getState().ojFormReducer; + let _errMsg = ''; const bool = testCases.some((item, i) => { if (i !== index) { + if (item['output'] === value) { + _errMsg=`与测试用例${index}的输入值重复了,请重新填写`; + } return item['output'] === value; } else { return false; @@ -502,7 +510,7 @@ export const testCaseOutputChange = (value, index) => { if (bool) { validate = { validateStatus: 'error', - errMsg: '输入值必须唯一' + errMsg: _errMsg }; } } diff --git a/public/react/src/redux/reducers/ojForUserReducer.js b/public/react/src/redux/reducers/ojForUserReducer.js index 6520f8954..60e7e6fd1 100644 --- a/public/react/src/redux/reducers/ojForUserReducer.js +++ b/public/react/src/redux/reducers/ojForUserReducer.js @@ -4,7 +4,7 @@ * @Github: * @Date: 2019-11-27 13:41:48 * @LastEditors: tangjiang - * @LastEditTime: 2019-12-10 10:09:59 + * @LastEditTime: 2019-12-19 14:49:03 */ import types from "../actions/actionTypes"; import { Base64 } from 'js-base64'; @@ -21,7 +21,9 @@ const initialState = { userTestInput: '', // 用户自定义输入值 recordDetail: {}, // 根据id号获取的记录详情 hack_identifier: '', // 用户界面编辑时 - editor_code: '' // 保存编辑代码 + editor_code: '', // 保存编辑代码 + notice: false, // 通知 + hadCodeUpdate: false, // 更新代码 }; const ojForUserReducer = (state = initialState, action) => { @@ -36,7 +38,8 @@ const ojForUserReducer = (state = initialState, action) => { const { hack, test_case } = action.payload; const { code }= hack; let tempCode = Base64.decode(code) - Object.assign(hack, {code: tempCode}); + let tempDesc = JSON.parse(hack.description); + Object.assign(hack, {code: tempCode, description: tempDesc}); return { ...state, hack: Object.assign({}, hack), @@ -121,6 +124,21 @@ const ojForUserReducer = (state = initialState, action) => { ...state, editor_code: action.payload } + case types.SAVE_USE_TEST_CASE_VALUE: + return { + ...state, + userTestInput: action.payload.input + } + case types.SAVE_NOTICE_COUNT: + return { + ...state, + notice: action.payload + }; + case types.AUTO_UPDATE_CODE: + return { + ...state, + hadCodeUpdate: action.payload + }; default: return state; } diff --git a/public/react/src/redux/reducers/ojFormReducer.js b/public/react/src/redux/reducers/ojFormReducer.js index c2ba0f4d8..39af4a5f8 100644 --- a/public/react/src/redux/reducers/ojFormReducer.js +++ b/public/react/src/redux/reducers/ojFormReducer.js @@ -4,7 +4,7 @@ * @Github: * @Date: 2019-11-20 16:40:32 * @LastEditors: tangjiang - * @LastEditTime: 2019-12-13 11:54:35 + * @LastEditTime: 2019-12-17 16:19:04 */ import { Base64 } from 'js-base64'; import types from '../actions/actionTypes'; @@ -176,7 +176,7 @@ const ojFormReducer = (state = initialState, action) => { const currentOjForm = { name, // 任务名称 language, - description, + description: JSON.parse(description), difficult, category, openOrNot: 1, diff --git a/public/react/src/services/ojService.js b/public/react/src/services/ojService.js index e13b66397..373805b73 100644 --- a/public/react/src/services/ojService.js +++ b/public/react/src/services/ojService.js @@ -4,10 +4,11 @@ * @Github: * @Date: 2019-11-20 10:55:38 * @LastEditors: tangjiang - * @LastEditTime: 2019-12-13 17:03:47 + * @LastEditTime: 2019-12-17 14:10:37 */ import axios from 'axios'; +import { func } from 'prop-types'; export async function fetchOJList (params) { console.log('传递的参数: ', params); @@ -125,3 +126,15 @@ export async function fetchUserInfoForNew () { const url = `/problems/new.json`; return axios.get(url); } + +// 文件上传 +export async function fetchUploadImage (file) { + const url = `/attachments.json`; + return axios.post(url, file) +} + +// 根据id号获取图片url +export async function fetchUploadImageUrl (id) { + const url = `/attachments/${id}`; + return axios.get(url); +} From c69f06b746b1e41c577530df9d33357073210aed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=9E=97?= <904079904@qq.com> Date: Thu, 19 Dec 2019 18:24:30 +0800 Subject: [PATCH 19/39] =?UTF-8?q?=E6=96=B0=E7=89=88=E5=AD=A6=E9=99=A2?= =?UTF-8?q?=E7=BB=9F=E8=AE=A1=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/react/src/App.js | 10 +- public/react/src/college/College.js | 1259 +++++++++++++++++ .../college/colleagechart/Colleagechart.js | 84 ++ .../college/colleagechart/Colleagechartzu.js | 149 ++ .../src/college/colleagecss/colleage.css | 213 +++ 5 files changed, 1714 insertions(+), 1 deletion(-) create mode 100644 public/react/src/college/College.js create mode 100644 public/react/src/college/colleagechart/Colleagechart.js create mode 100644 public/react/src/college/colleagechart/Colleagechartzu.js create mode 100644 public/react/src/college/colleagecss/colleage.css diff --git a/public/react/src/App.js b/public/react/src/App.js index 4694d57da..03cad7110 100644 --- a/public/react/src/App.js +++ b/public/react/src/App.js @@ -71,6 +71,11 @@ const Otherlogin=Loadable({ loader: () => import('./modules/login/Otherlogin'), loading: Loading, }) +// 学院统计 +const College = Loadable({ + loader: () => import('./college/College'), + loading: Loading +}) const Otherloginstart=Loadable({ loader: () => import('./modules/login/Otherloginstart'), @@ -614,7 +619,10 @@ class App extends Component { {/*/>*/} <Route path="/shixuns/new" component={Newshixuns}> </Route> - + <Route path="/colleges/:id/statistics" + render={ + (props) => (<College {...this.props} {...props} {...this.state} />) + }/> {/* jupyter */} <Route path="/tasks/:identifier/jupyter/" render={ diff --git a/public/react/src/college/College.js b/public/react/src/college/College.js new file mode 100644 index 000000000..bc43252b7 --- /dev/null +++ b/public/react/src/college/College.js @@ -0,0 +1,1259 @@ +import React, {Component} from "react"; +import {Link, NavLink} from 'react-router-dom'; +import {WordsBtn, ActionBtn,SnackbarHOC,getImageUrl} from 'educoder'; +import axios from 'axios'; +import { + notification, + Spin, + Table, + Pagination, +} 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 './colleagecss/colleage.css'; +import Shixunechart from "../modules/courses/shixunHomework/shixunreport/Shixunechart"; +class College extends Component { + constructor(props) { + super(props); + // this.answerMdRef = React.createRef(); + this.state = { + coursesloading:false, + columns: [ + { + title: '名称', + dataIndex: 'name', + key: 'name', + align: 'center', + className: "edu-txt-center font-14 maxnamewidth247", + render: (text, record) => ( + <a href={`/courses/${record.id}/students`} title={record.name} target="_blank" className="d-inline-block text-truncate maxnamewidth247" + style={{ + maxWidth:'220px', + color:'#007bff', + }}>{ + record.name + }</a> + ) + }, + { + title: '管理教师', + dataIndex: 'teachers', + key: 'teachers', + align: 'center', + className: "edu-txt-center font-14 maxnamewidth340", + render: (text, record) => ( + <span className="maxnamewidth340"> + { + record.teachers + } + </span> + ) + }, + { + title: '评测次数', + dataIndex: 'times', + key: 'times', + align: 'center', + className: "edu-txt-center font-14 maxnamewidth175", + render: (text, record) => ( + <span> + { + record.evaluating_count + } + </span> + ), + }, + { + title: '学生', + key: 'student', + dataIndex: 'student', + align: 'center', + className: "edu-txt-center font-14 maxnamewidth255", + render: (text, record) => ( + <span> + { + record.student_count + } + </span> + ) + }, + { + title: '实训作业', + dataIndex: 'training', + key: 'training', + align: 'center', + className: "edu-txt-center font-14", + render: (text, record) => ( + <span> + { + record.shixun_work_count + } + </span> + ) + + }, + { + title: '资源', + dataIndex: 'resources', + key: 'resources', + align: 'center', + className: "edu-txt-center font-14", + render: (text, record) => ( + <span> + { + record.attachment_count + } + </span> + ), + }, + { + title: '帖子', + dataIndex: 'posts', + key: 'posts', + align: 'center', + className: "edu-txt-center font-14", + render: (text, record) => ( + <span>{ + record.message_count + }</span> + ) + }, + { + title: '其它任务', + dataIndex: 'othertasks', + key: 'othertasks', + align: 'center', + className: "edu-txt-center font-14", + render: (text, record) => ( + <span> + { + record.other_work_count + } + </span> + ) + }, + { + title: '状态', + dataIndex: 'states', + key: 'states', + align: 'center', + className: "edu-txt-center font-14", + render: (text, record) => ( + <span className={record.is_end?'':'color-huang'}> + { + record.is_end? + "已结束" + : + "正在进行" + } + </span> + ) + }, + { + title: '时间', + dataIndex: 'timemy', + key: 'timemy', + align: 'center', + className: "edu-txt-center font-14", + render: (text, record) => ( + <span > + { + record.activity_time + } + </span> + ) + }, + ], + page:1, + limit:10, + total_users:50, + teachersloading:false, + teacherranking:[ + { + title: '排名', + dataIndex: 'ranking', + key: 'ranking', + align: 'center', + className: "edu-txt-center font-14", + render: (text, record) => ( + <span> + { + record.id + } + </span> + ) + }, + { + title: '姓名', + dataIndex: 'name', + key: 'name', + align: 'center', + className: "edu-txt-center font-14 maxnamewidth105", + render: (text, record) => ( + <a href={`/users/${record.login}`} title={record.name} target="_blank" className="task-hide maxnamewidth105" style={{ + color:'#007bff', + + }}> { + record.name + } + </a> + ) + }, + { + title: '管理课堂', + dataIndex: 'classroom', + key: 'classroom', + align: 'center', + className: "edu-txt-center font-14 maxnamewidth175", + render: (text, record) => ( + <span> + { + record.course_count + } + </span> + ), + }, + { + title: '已发布实训作业', + key: 'assignment', + dataIndex: 'assignment', + align: 'center', + className: "edu-txt-center font-14 maxnamewidth255", + render: (text, record) => ( + <span> + { + record.shixun_work_count + } + </span> + ) + }, + { + title: '未发布实训作业', + dataIndex: 'released', + key: 'released', + align: 'center', + className: "edu-txt-center font-14", + render: (text, record) => ( + <span> + { + record.un_shixun_work_count + } + </span> + ) + + }, + { + title: '学生数', + dataIndex: 'studentnumber', + key: 'studentnumber', + align: 'center', + className: "edu-txt-center font-14", + render: (text, record) => ( + <span> + { + record.student_count + } + </span> + ), + }, + { + title: '完成率', + dataIndex: 'completionrate', + key: 'completionrate', + align: 'center', + className: "edu-txt-center font-14", + render: (text, record) => ( + <span> + { + record.complete_rate+"%" + } + </span> + ) + }, + { + title: '发布实训', + dataIndex: 'releasetraining', + key: 'releasetraining', + align: 'center', + className: "edu-txt-center font-14", + render: (text, record) => ( + <span className="color-blue"> + { + record.publish_shixun_count + } + </span> + ) + } + ], + studentranking:[ + { + title: '排名', + dataIndex: 'ranking', + key: 'ranking', + align: 'center', + className: "edu-txt-center font-14", + width:'100px', + render: (text, record) => ( + <span> + { + record.id===1? <img width="18px" height="22px" className="mt8" src={getImageUrl("images/educoder/competition/1.png")}/> + :record.id===2? + <img width="18px" height="22px" className="mt8" src={getImageUrl("images/educoder/competition/2.png")}/> + :record.id===3? + <img width="18px" height="22px" className="mt8" src={getImageUrl("images/educoder/competition/3.png")}/> + :record.id + } + </span> + ) + }, + { + title: '姓名', + dataIndex: 'name', + key: 'name', + align: 'center', + className: "edu-txt-center font-14 maxnamewidth105", + width:'100px', + render: (text, record) => ( + <a href={`/users/${record.login}`} title={record.name} target="_blank" className="task-hide maxnamewidth105" style={{ + color:'#007bff', + + }}> { + record.name + } + </a> + ) + }, + { + title: '学号', + dataIndex: 'studentid', + key: 'studentid', + align: 'center', + className: "edu-txt-center font-14 maxnamewidth175", + render: (text, record) => ( + <span> + { + record.student_id + } + </span> + ), + }, + { + title: '完成实训', + key: 'training', + dataIndex: 'training', + align: 'center', + className: "edu-txt-center font-14 maxnamewidth255", + render: (text, record) => ( + <span> + { + record.shixun_count + } + </span> + ) + }, + { + title: '在学实训', + dataIndex: 'learning', + key: 'learning', + align: 'center', + className: "edu-txt-center font-14", + render: (text, record) => ( + <span> + { + record.study_shixun_count + } + </span> + ) + + }, + { + title: '金币', + dataIndex: 'goldcoin', + key: 'goldcoin', + align: 'center', + className: "edu-txt-center font-14", + render: (text, record) => ( + <span> + { + record.grade + } + </span> + ), + }, + { + title: '经验值', + dataIndex: 'empirical', + key: 'empirical', + align: 'center', + className: "edu-txt-center font-14", + render: (text, record) => ( + <span style={{ + color:'#17a2b8' + }}> + { + record.experience + } + </span> + ) + }, + ], + school:"", + teachers_count:null, + students_count:null, + courses_count:null, + shixuns_count:null, + shixun_report_count:null, + shixun_time:null, + courses:null, + course_count:0, + pages:1, + limits:10, + teachers:null, + teacher_count:0, + students:null, + student_count:0, + shixun_chart_data:null, + shixun_chart_datanames:null, + studentionsnames:null, + studentionsvalues:null + } + + } + + + componentDidMount(){ + console.log("College"); + console.log(this.props.match.params.id); + this.gettop(); + this.Numberofinternshipreports(); + this.Actualcombattimeoftrainees(); + this.Classnumber(1,10); + this.Teacherranking(1,10); + this.Studentranking(1,10); + this.Onlinetraining(); + this.Hottest(); + } + //头部 + gettop=()=>{ + const id =this.props.match.params.id; + const url=`/colleges/${id}/statistics.json`; + axios.get(url).then((response) => { + if(response===null||response===undefined){ + this.setState({ + teachers_count:0, + students_count:0, + courses_count:0, + shixuns_count:0, + school:"", + }) + return + } + if (response.data.status === 403||response.data.status === 401||response.data.status === 500) { + this.setState({ + teachers_count:0, + students_count:0, + courses_count:0, + shixuns_count:0, + school:"", + }) + }else{ + this.setState({ + teachers_count:response.data.teachers_count, + students_count:response.data.students_count, + courses_count:response.data.courses_count, + shixuns_count:response.data.shixuns_count, + school:response.data.school, + }) + } + }).catch((error) => { + console.log(error) + this.setState({ + teachers_count:0, + students_count:0, + courses_count:0, + shixuns_count:0, + school:"", + }) + }); + } + + //获取实训报告数 + Numberofinternshipreports=()=>{ + const id =this.props.match.params.id; + const url=`/colleges/${id}/shixun_report_count.json`; + axios.get(url).then((response) => { + if(response===null||response===undefined){ + this.setState({ + shixun_report_count:0, + }) + return + } + if (response.data.status === 403||response.data.status === 401||response.data.status === 500) { + this.setState({ + shixun_report_count:0, + }) + }else{ + if (response.data.status === -1){ + this.setState({ + shixun_report_count:0, + }) + return + } + this.setState({ + shixun_report_count:response.data.shixun_report_count, + }) + } + }).catch((error) => { + console.log(error) + this.setState({ + shixun_report_count:0, + }) + }); + } + + //学员实战时间 + Actualcombattimeoftrainees=()=>{ + const id =this.props.match.params.id; + const url=`/colleges/${id}/shixun_time.json`; + axios.get(url).then((response) => { + if(response===null||response===undefined){ + this.setState({ + shixun_time:0, + }) + return + } + if (response.data.status === 403||response.data.status === 401||response.data.status === 500) { + this.setState({ + shixun_time:0, + }) + }else{ + if (response.data.status === -1){ + this.setState({ + shixun_time:0, + }) + return + } + this.setState({ + shixun_time:response.data.shixun_time, + }) + } + }).catch((error) => { + console.log(error) + this.setState({ + shixun_time:0, + }) + }); + } + + //课堂信息 + Classnumber=(page,per_page)=>{ + const id =this.props.match.params.id; + const url=`/colleges/${id}/course_statistics.json`; + this.setState({ + coursesloading:true + }) + axios.get(url,{params:{ + page:page, + per_page:per_page, + } + }).then((response) => { + if(response===null||response===undefined){ + this.setState({ + courses:[], + course_count:0 + }) + return + } + if (response.data.status === 403||response.data.status === 401||response.data.status === 500) { + this.setState({ + courses:[], + course_count:0 + }) + }else{ + if (response.data.status === -1){ + this.setState({ + courses:[], + course_count:0 + }) + return + } + this.setState({ + courses:response.data.courses, + course_count:response.data.course_count, + page:page, + limit:per_page + }) + } + this.setState({ + coursesloading:false + }) + }).catch((error) => { + this.setState({ + courses:[], + course_count:0, + coursesloading:false + }) + }); + } + + //教师排名 + Teacherranking=(page,per_page)=>{ + const id =this.props.match.params.id; + const url=`/colleges/${id}/teachers.json`; + this.setState({ + teachersloading:true + }) + axios.get(url,{params:{ + page:page, + per_page:per_page, + } + }).then((response) => { + if(response===null||response===undefined){ + this.setState({ + teachers:[], + teacher_count:0 + }) + return + } + if (response.data.status === 403||response.data.status === 401||response.data.status === 500) { + this.setState({ + teachers:[], + teacher_count:0 + }) + }else{ + if (response.data.status === -1){ + this.setState({ + teachers:[], + teacher_count:0 + }) + return + } + let teachers=[]; + if(response.data.teachers){ + for(let i=0;i<response.data.teachers.length;i++){ + let datay={ + id:(i+(page-1)*10)+1, + login: response.data.teachers[i].login, + name: response.data.teachers[i].name, // 姓名 + course_count: response.data.teachers[i].course_count, // 课堂数 + shixun_work_count:response.data.teachers[i].shixun_work_count, // 已发布实训作业 + un_shixun_work_count:response.data.teachers[i].un_shixun_work_count, // 未发布实训作业 + student_count: response.data.teachers[i].student_count, // 学生数 + complete_rate: response.data.teachers[i].complete_rate, // 完成率 + publish_shixun_count: response.data.teachers[i].publish_shixun_count, // 发布实训数 + } + teachers.push(datay); + + } + + } + this.setState({ + teachers:teachers, + teacher_count:response.data.teacher_count, + pages:page, + limits:per_page, + }) + } + this.setState({ + teachersloading:false + }) + }).catch((error) => { + this.setState({ + teachers:[], + teacher_count:0, + teachersloading:false + }) + }); + } + //学生排名 + + Studentranking=(page,per_page)=>{ + const id =this.props.match.params.id; + const url=`/colleges/${id}/student_shixun.json`; + this.setState({ + studentsloading:true + }) + axios.get(url,{params:{ + page:page, + per_page:per_page, + } + }).then((response) => { + if(response===null||response===undefined){ + this.setState({ + students:[], + student_count:0, + }) + return + } + if (response.data.status === 403||response.data.status === 401||response.data.status === 500) { + this.setState({ + students:[], + student_count:0, + }) + }else{ + if (response.data.status === -1){ + this.setState({ + students:[], + student_count:0, + }) + return + } + let students=[]; + if(response.data.teachers){ + for(let i=0;i<response.data.teachers.length;i++){ + let datay={ + id:(i+(page-1)*10)+1, + login: response.data.teachers[i].login, + name: response.data.teachers[i].name, // 姓名 + student_id: response.data.teachers[i].student_id, + shixun_count:response.data.teachers[i].shixun_count, + study_shixun_count:response.data.teachers[i].study_shixun_count, + grade: response.data.teachers[i].grade, + experience: response.data.teachers[i].experience, + } + students.push(datay); + } + } + this.setState({ + students:students, + student_count:response.data.student_count, + pagess:page, + limitss:per_page, + }) + } + this.setState({ + studentsloading:false + }) + }).catch((error) => { + this.setState({ + students:[], + student_count:0, + studentsloading:false + }) + }); + } + + //在线实训情况 + Onlinetraining=()=>{ + const id =this.props.match.params.id; + const url=`/colleges/${id}/shixun_chart_data.json`; + axios.get(url).then((response) => { + if (response.data.status === 403||response.data.status === 401||response.data.status === 500) { + this.setState({ + shixun_chart_data:[], + shixun_chart_datanames:[] + }) + }else{ + if (response.data.status === -1){ + this.setState({ + shixun_chart_data:[], + shixun_chart_datanames:[] + }) + return + } + + this.setState({ + shixun_chart_data:response.data.data, + shixun_chart_datanames:response.data.names + }) + } + }).catch((error) => { + this.setState({ + shixun_chart_data:[], + shixun_chart_datanames:[] + }) + }); + } + //最热测评 + Hottest=()=>{ + const id =this.props.match.params.id; + const url=`/colleges/${id}/student_hot_evaluations.json`; + axios.get(url).then((response) => { + if (response.data.status === 403||response.data.status === 401||response.data.status === 500) { + this.setState({ + studentionsnames: [], + studentionsvalues: [] + }) + }else { + if (response.data.status === -1) { + this.setState({ + studentionsnames: [], + studentionsvalues: [] + }) + return + } + this.setState({ + studentionsnames: response.data.names, + studentionsvalues: response.data.values + }) + } + }).catch((error) => { + this.setState({ + studentionsnames: [], + studentionsvalues: [] + }) + }); + } + + table1handleChange(){ + + } + + //塞选 + paginationonChange=(pageNumber)=>{ + this.Classnumber(pageNumber,10); + } + + paginationonChanges=(pageNumber)=>{ + this.Teacherranking(pageNumber,10); + } + paginationonChangess=(pageNumber)=>{ + this.Studentranking(pageNumber,10); + } + render() { + let {columns,page,limit,total_users,teacherranking,studentranking, + teachers_count,students_count, courses_count, shixuns_count,shixun_report_count,shixun_time,courses,course_count,school,teachers, + pages,limits, teacher_count,teachersloading,coursesloading,pagess,limitss,studentsloading,students,student_count,shixun_chart_data, + shixun_chart_datanames, studentionsnames,studentionsvalues + } = this.state; + + return ( + <div className="newMain clearfix edu-back-eeee"> + <div className="yslstatistic-header intermediatecenter" > + <div className="intermediatecenter " style={{ + maxWidth:"1300px", + width:"1300px", + height: '100%', + }}> + <div className="yslstatistic-header-title">{school}</div> + <div className="yslstatistic-header-content"> + <div className="yslstatistic-header-item"> + {/*//教师1*/} + <div className="yslstatistic-header-item-label"> + 教师 + </div> + <div className="yslstatistic-header-item-content"> + {teachers_count?teachers_count:0} + </div> + </div> + + <div className="yslstatistic-header-item"> + <div className="yslstatistic-header-item-label"> + 学生 + </div> + <div className="yslstatistic-header-item-content"> + {students_count?students_count:0} + </div> + </div> + + <div className="yslstatistic-header-item"> + <div className="yslstatistic-header-item-label"> + 课堂 + </div> + <div className="yslstatistic-header-item-content"> + {courses_count?courses_count:0} + </div> + </div> + + <div className="yslstatistic-header-item"> + <div className="yslstatistic-header-item-label"> + 共建实训 + </div> + <div className="yslstatistic-header-item-content"> + {shixuns_count?shixuns_count:0} + </div> + </div> + {/*//教师2*/} + + + + + </div> + </div> + </div> + <div className={"educontent edu-back-white mt-4"} style={{width: "1300px"}}> + <p className="h4 linjibenshiyong"> + 基本使用情况 + </p> + {/*基本使用情况1*/} + <div className="jibenshiyong100 sortinxdirection yinyin"> + <p className="yslstatistic-base-item-label"> + 教师 + </p> + <p className="yslstatistic-base-item-label"> + 学生 + </p> + <p className="yslstatistic-base-item-label"> + 课堂 + </p> + <p className="yslstatistic-base-item-label"> + 共建实训 + </p> + <p className="yslstatistic-base-item-label"> + 实习报告 + </p> + <p className="yslstatistic-base-item-label"> + 学员实战时间 + </p> + </div> + + + {/*基本使用情况2*/} + <div className="jibenshiyong100 sortinxdirection yinyin"> + <div className="yslstatistic-base-item-labels"> + { + teachers_count? + <div className="yslstatistic-base-item-labelsp"> {teachers_count}<span className="yslstatistic-base-item-labelsspan">人</span></div> + : + <Spin/> + } + </div> + <div className="yslstatistic-base-item-labels"> + { + students_count? + <div className="yslstatistic-base-item-labelsp">{students_count}<span className="yslstatistic-base-item-labelsspan">人</span></div> + : + <Spin/> + } + </div> + <div className="yslstatistic-base-item-labels"> + { + courses_count? + <div className="yslstatistic-base-item-labelsp">{courses_count}<span className="yslstatistic-base-item-labelsspan">个</span></div> + : + <Spin/> + } + </div> + <div className="yslstatistic-base-item-labels"> + { + shixuns_count? + <div className="yslstatistic-base-item-labelsp">{shixuns_count}<span className="yslstatistic-base-item-labelsspan">个</span></div> + : + <Spin/> + } + </div> + <div className="yslstatistic-base-item-labels"> + { + shixun_report_count? + <div className="yslstatistic-base-item-labelsp">{shixun_report_count}<span className="yslstatistic-base-item-labelsspan">个</span></div> + : + <Spin/> + } + </div> + <div className="yslstatistic-base-item-labels"> + { + shixun_time? + <div className="yslstatistic-base-item-labelsp">{shixun_time}<span className="yslstatistic-base-item-labelsspan">天</span></div> + : + <Spin/> + } + </div> + </div> + {/*基本使用情况3结束*/} + </div> + + + <div className={"educontent edu-back-white mt-4 yinyin"} style={{width: "1300px"}}> + <p className="statistic-label linjibenshiyong"> + 课堂 + </p> + { + courses===null? + <div className="intermediatecenter" style={{ + height:'500px' + }}> + <Spin tip="正在加载..."/> + </div> + + : + JSON.stringify(courses) === "[]" ? + <NoneData> + + </NoneData> + : + <div style={{width: "1300px"}}> + <div className={"justify break_full_word new_li edu-back-white"} + style={{minHeight: "480px"}}> + <style>{` + .ant-spin-nested-loading > div > .ant-spin .ant-spin-dot { + top: 72%;} + } + .ysltableows2 .ant-table-thead > tr > th{ + padding: 9px; + } + + + .ysltableows2 .ant-table-tbody > tr > td { + padding: 15px; + } + + .mysjysltable1 .ant-table-thead > tr > th{ + padding: 9px; + } + + .mysjysltable1 .ant-table-tbody > tr > td { + padding: 15px; + } + .ysltableows2 .ant-table-thead > tr > th{ + background: #F5F5F5; + } + `}</style> + <div className="edu-table edu-back-white ysltableows2"> + {courses === undefined ? "" : <Table + dataSource={courses} + columns={columns} + className="mysjysltable1" + pagination={false} + loading={coursesloading} + // onChange={this.TablePaginationsy} + />} + </div> + </div> + { + course_count>=11? + <div style={{ + width:'100%', + padding:'40px' + }}> + <div className="edu-txt-center "> + <Pagination showQuickJumper current={page} onChange={this.paginationonChange} + pageSize={limit} + total={course_count}></Pagination> + </div> + + </div> + :"" + } + + </div> + } + + + </div> + + + <div className={"educontent edu-back-white yinyin mt-4 sortinxdirection"} style={{width: "1300px"}}> + <div className=" verticallayout" style={{ + width: "63%" + }}> + <p className="statistic-label ysllinjibenshiyong yinyin"> + 教师排名 + </p> + { + teachers===null? + <div className="intermediatecenter" style={{ + height:'500px' + }}> + <Spin tip="正在加载..."/> + </div> + + : + JSON.stringify(teachers) === "[]" ? + <NoneData> + + </NoneData> + : + <div className={"justify break_full_word new_li edu-back-white "} + style={{minHeight: "480px"}}> + <style>{` + .ant-spin-nested-loading > div > .ant-spin .ant-spin-dot { + top: 72%;} + } + .ysltableows2 .ant-table-thead > tr > th{ + padding: 9px; + } + + + .ysltableows2 .ant-table-tbody > tr > td { + padding: 15px; + } + + .mysjysltable1 .ant-table-thead > tr > th{ + padding: 9px; + } + + .mysjysltable1 .ant-table-tbody > tr > td { + padding: 15px; + } + .ysltableows2 .ant-table-thead > tr > th{ + background: #F5F5F5; + } + + `}</style> + <div className="edu-table edu-back-white ysltableows2"> + {teachers === undefined ? "" : <Table + dataSource={teachers} + columns={teacherranking} + className="mysjysltable1" + pagination={false} + loading={teachersloading} + // onChange={this.TablePaginationsy} + />} + </div> + </div> + } + + + + {/*<div style={{*/} + {/* width:'100%',*/} + {/* padding:'40px'*/} + {/*}}>*/} + {/* <div className="edu-txt-center ">*/} + {/* <Pagination showQuickJumper current={pages} onChange={this.paginationonChanges}*/} + {/* pageSize={limits}*/} + {/* total={teacher_count}></Pagination>*/} + {/* </div>*/} + + {/*</div>*/} + </div> + + <div className="" style={{ + width: "37%" + }}><div className="yslslinjibenshiyong" style={{ + height: "100%" + }}> + <p className="statistic-label ysllinjibenshiyong"> + 在线实训情况 + </p> + { + shixun_chart_data===null? + <div className="intermediatecenter" style={{ + height:'500px' + }}> + <Spin tip="正在加载..."/> + </div> + + : + JSON.stringify(shixun_chart_data) === "[]" ? + <NoneData> + + </NoneData> + : + <Colleagechart data={shixun_chart_data} datanane={shixun_chart_datanames}> + + </Colleagechart> + } + + </div> + </div> + </div> + + + <div className={"educontent edu-back-white yinyin mt-4 sortinxdirection mb80"} style={{width: "1300px"}}> + <div className=" verticallayout" style={{ + width: "63%" + }}> + <p className="statistic-label ysllinjibenshiyong yinyin "> + 学生排名 + </p> + { + students === null ? + <div className="intermediatecenter" style={{ + height: '500px' + }}> + <Spin tip="正在加载..."/> + </div> + + : + JSON.stringify(students) === "[]" ? + <NoneData> + + </NoneData> + : + <div className={"justify break_full_word new_li edu-back-white "} + style={{minHeight: "480px"}}> + <style>{` + .ant-spin-nested-loading > div > .ant-spin .ant-spin-dot { + top: 72%;} + } + .ysltableows2 .ant-table-thead > tr > th{ + padding: 9px; + } + + + .ysltableows2 .ant-table-tbody > tr > td { + padding: 15px; + } + + .mysjysltable1 .ant-table-thead > tr > th{ + padding: 9px; + } + + .mysjysltable1 .ant-table-tbody > tr > td { + padding: 15px; + } + .ysltableows2 .ant-table-thead > tr > th{ + background: #F5F5F5; + } + `}</style> + <div className="edu-table edu-back-white ysltableows2"> + {students === undefined ? "" : <Table + dataSource={students} + columns={studentranking} + 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={{ + width: "37%" + }}> + + <div className="yslslinjibenshiyong" style={{ + height: "100%" + }}> + <p className="statistic-label ysllinjibenshiyong"> + 最热评测 + </p> + { + studentionsnames===null? + <div className="intermediatecenter" style={{ + height:'500px' + }}> + <Spin tip="正在加载..."/> + </div> + + : + JSON.stringify(studentionsnames) === "[]" ? + <NoneData> + + </NoneData> + : + <Colleagechartzu data={studentionsnames} datavule={studentionsvalues}> + + </Colleagechartzu> + } + + + </div> + </div> + </div> + </div> + ) + } +} +export default SnackbarHOC() (TPMIndexHOC ( College )); + + diff --git a/public/react/src/college/colleagechart/Colleagechart.js b/public/react/src/college/colleagechart/Colleagechart.js new file mode 100644 index 000000000..fca01280a --- /dev/null +++ b/public/react/src/college/colleagechart/Colleagechart.js @@ -0,0 +1,84 @@ +import React, {Component} from "react"; +import {WordsBtn} from 'educoder'; +import {Table} from "antd"; +import {Link,Switch,Route,Redirect} from 'react-router-dom'; +const echarts = require('echarts'); + + + +function startechart(data,datanane){ + var effChart = echarts.init(document.getElementById('shixun_skill_chart')); + + var option = { + + tooltip : { + trigger: 'item', + formatter: "{d}% <br/>" + }, + legend: { + // orient: 'vertical', + // top: 'middle', + bottom: 50, + left: 'center', + data: datanane + }, + series : [ + { + type: 'pie', + radius : '65%', + center: ['50%', '35%'], + selectedMode: 'single', + data:data, + itemStyle: { + emphasis: { + shadowBlur: 10, + shadowOffsetX: 0, + shadowColor: 'rgba(0, 0, 0, 0.5)' + } + } + } + ] + }; + effChart.setOption(option); +} +class Colleagechart extends Component { + + constructor(props) { + super(props); + this.state = { + } + } + + componentDidMount() { + startechart(this.props.data,this.props.datanane) + } + + + componentDidUpdate = (prevProps) => { + if (prevProps.data!= this.props.data) { + startechart(this.props.data,this.props.datanane) + } + } + + + render() { + let {data}=this.props; + + return ( + <div> + + <div + style={{ width:'100%',height:'600px'}} + id="shixun_skill_chart"> + </div> + + + + + </div> + + ) + } +} + +export default Colleagechart; diff --git a/public/react/src/college/colleagechart/Colleagechartzu.js b/public/react/src/college/colleagechart/Colleagechartzu.js new file mode 100644 index 000000000..5c0269700 --- /dev/null +++ b/public/react/src/college/colleagechart/Colleagechartzu.js @@ -0,0 +1,149 @@ +import React, {Component} from "react"; +import {WordsBtn} from 'educoder'; +import {Table} from "antd"; +import {Link,Switch,Route,Redirect} from 'react-router-dom'; +const echarts = require('echarts'); + + + +function startechart(names, values){ + var effChart = echarts.init(document.getElementById('shixun_skill_charts')); + + var Color = ['#962e66', '#623363', '#CCCCCC', '#9A9A9A', '#FF8080', '#FF80C2', '#B980FF', '#80B9FF', '#6FE9FF', '#4DE8B4', '#F8EF63', '#FFB967']; + + var option = { + backgroundColor: '#fff', + grid: { + left: '3%', + right: '8%', + bottom: '15%', + containLabel: true + }, + + 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: 'value', + axisTick: { + show: false + }, + axisLine: { + show: true, + lineStyle: { + color: '#CCCCCC' + } + }, + splitLine: { + show: false, + lineStyle: { + color: '#CCCCCC' + } + }, + axisLabel: { + textStyle: { + color: '#656565', + fontWeight: 'normal', + fontSize: '12' + }, + formatter: '{value}' + } + }, + yAxis: { + type: 'category', + axisLine: { + lineStyle: { + color: '#cccccc' + } + }, + splitLine: { + show: false + }, + axisTick: { + show: false + }, + splitArea: { + show: false + }, + axisLabel: { + inside: false, + textStyle: { + color: '#656565', + fontWeight: 'normal', + fontSize: '12' + } + }, + data: names + }, + series: [{ + name: '', + type: 'bar', + itemStyle: { + normal: { + show: true, + color: function(params) { + return Color[params.dataIndex] + }, + barBorderRadius: 50, + borderWidth: 0, + borderColor: '#333' + } + }, + barGap: '0%', + barCategoryGap: '50%', + data: values + } + + ] + }; + effChart.setOption(option); +} +class Colleagechartzu extends Component { + + constructor(props) { + super(props); + this.state = { + } + } + + componentDidMount() { + startechart(this.props.data,this.props.datavule) + } + + + componentDidUpdate = (prevProps) => { + if (prevProps.data!= this.props.data) { + startechart(this.props.data,this.props.datavule) + } + } + + + render() { + let {data}=this.props; + + return ( + <div> + + <div + style={{ width:'100%',height:'600px'}} + id="shixun_skill_charts"> + </div> + + + + + </div> + + ) + } +} + +export default Colleagechartzu; diff --git a/public/react/src/college/colleagecss/colleage.css b/public/react/src/college/colleagecss/colleage.css new file mode 100644 index 000000000..801b86603 --- /dev/null +++ b/public/react/src/college/colleagecss/colleage.css @@ -0,0 +1,213 @@ +.yslstatistic-header { + width: 100%; + height: 240px; + background-image: url('/images/educoder/statistics.jpg'); + background-size: 100% 100%; +} +.yslborder{ + border: 1px solid; +} +.yslstatistic-header-title{ + flex: 1; + display: flex; + align-items: center; + color: #4CACFF; + font-size: 32px; +} +.yslstatistic-header-content{ + width: 100%; + display: flex; + justify-content: space-around; +} +.yslstatistic-header-item{ + margin-bottom: 22px; + display: flex; + flex-direction: column; + align-items: center; + color: #fff; +} +.yslstatistic-header-item-label{ + color: #989898; +} + +.yslstatistic-base-item-label{ + width: 217px; + text-align: center; + font-size: 16px; + height: 48px; + line-height: 48px; + color: #686868; + background: #F5F5F5; + border-top: 1px solid #EBEBEB; +} +.yslstatistic-base-item-labels{ + width: 217px; + text-align: center; + height: 100px; + line-height: 100px; + background: #ffffff; + border-top: 1px solid #EBEBEB; + border-bottom: 1px solid #EBEBEB; +} +.yslstatistic-base-item-labelsp{ + color: #000000; + font-size: 24px; +} +.yslstatistic-base-item-labelsspan{ + color: #000000; + margin-left: 5px; + font-size: 16px; +} +.jibenshiyong100{ + width: 100%; +} + +.yslstatistic-header-item-content{ + font-size: 24px; +} +/* 中间居中 */ +.intermediatecenter{ + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; +} +/* 简单居中 */ +.intermediatecenterysls{ + display: flex; + align-items: center; +} +.spacearound{ + display: flex; + justify-content: space-around; + +} +.spacebetween{ + display: flex; + justify-content: space-between; +} +/* 头顶部居中 */ +.topcenter{ + display: -webkit-flex; + flex-direction: column; + align-items: center; + +} + + +/* x轴正方向排序 */ +/* 一 二 三 四 五 六 七 八 */ +.sortinxdirection{ + display: flex; + flex-direction:row; +} +/* x轴反方向排序 */ +/* 八 七 六 五 四 三 二 一 */ +.xaxisreverseorder{ + display: flex; + flex-direction:row-reverse; +} +/* 垂直布局 正方向*/ +/* 一 + 二 + 三 + 四 + 五 + 六 + 七 + 八 */ +.verticallayout{ + display: flex; + flex-direction:column; +} +/* 垂直布局 反方向*/ +.reversedirection{ + display: flex; + flex-direction:column-reverse; +} + +.h4{ + font-size: 1.5rem; + font-weight: 500 !important; +} +.ysllinjibenshiyong{ + font-weight: 500; + line-height: 1.2; + padding: 2rem 1.25rem; + border-bottom: unset; + background:#fff; +} +.linjibenshiyong{ + font-weight: 500; + line-height: 1.2; + padding: 2rem 1.25rem; + border-bottom: unset; + background:#fff; + box-shadow:0px 6px 12px 0px rgba(0,0,0,0.1); + border-radius:2px; +} +.yslslinjibenshiyong{ + font-weight: 500; + line-height: 1.2; + border-bottom: unset; + box-shadow:0px 6px 12px 0px rgba(0,0,0,0.1); + border-radius:2px; +} +.yinyin{ + background: #fff; + box-shadow:0px 6px 12px 0px rgba(0,0,0,0.1); + border-radius:2px; +} +.edu-back-eeee{ + background:#EEEEEE !important; +} +.mt-4{ + margin-top: 1.5rem !important; +} + +.statistic-label{ + padding: 2rem 1.25rem; + font-size: 1.5rem; + font-weight: 400 !important; +} +.mb50{ + padding-bottom: 50px !important; +} +.mt40{ + margin-top: 40px; +} +.mb80{ + margin-bottom: 80px; +} +.task-hide{overflow:hidden; white-space: nowrap; text-overflow:ellipsis;} +a:hover{ + color:#0056b3; +} +.color-blue{ + color: #4CACFF; +} + +.color-huang{ + color:#ffc107 !important +} +.maxnamewidth105{ + max-width: 105px; + overflow:hidden; + text-overflow:ellipsis; + white-space:nowrap; + cursor: default; +} +.maxnamewidth247{ + max-width: 247px; + overflow:hidden; + text-overflow:ellipsis; + white-space:nowrap; + cursor: default; +} +.maxnamewidth340{ + max-width: 340px; + overflow:hidden; + text-overflow:ellipsis; + white-space:nowrap; + cursor: default; +} From 893c4840f77c29288819cd6f2e5ed51ec9f8525b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=98=8E?= <775174143@qq.com> Date: Thu, 19 Dec 2019 18:55:19 +0800 Subject: [PATCH 20/39] =?UTF-8?q?=E5=AE=9E=E8=AE=AD=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/react/src/modules/tpm/TPMBanner.js | 16 ++++++---------- public/react/src/modules/tpm/TPMIndex.js | 8 +------- 2 files changed, 7 insertions(+), 17 deletions(-) diff --git a/public/react/src/modules/tpm/TPMBanner.js b/public/react/src/modules/tpm/TPMBanner.js index 141bd87d9..77b82c6c6 100644 --- a/public/react/src/modules/tpm/TPMBanner.js +++ b/public/react/src/modules/tpm/TPMBanner.js @@ -58,15 +58,6 @@ class TPMBanner extends Component { } } - // star_info:[0, 0, 0, 0, 0, 0], - // star_infos:[0, 0, 0, 0, 0, 0], - // shixunsDetails:{}, - // shixunId: undefined, - // componentWillReceiveProps(newProps, newContext){ - // this.setState({ - // shixunsDetails: newProps.shixunsDetails - // }); - // } IEVersion = () => { var userAgent = navigator.userAgent; //取得浏览器的userAgent字符串 @@ -141,8 +132,11 @@ class TPMBanner extends Component { }) } } + } } + + componentDidMount() { let thiisie = this.IEVersion(); @@ -155,6 +149,7 @@ class TPMBanner extends Component { isIE: false }) } + } /* @@ -784,7 +779,8 @@ class TPMBanner extends Component { }; // // console.log(this.props.shixunsDetails&&this.props.shixunsDetails.is_jupyter) - + console.log(this.props) + console.log(this.state) return ( shixunsDetails === undefined ? "" : diff --git a/public/react/src/modules/tpm/TPMIndex.js b/public/react/src/modules/tpm/TPMIndex.js index e032bb91f..c44d8ce51 100644 --- a/public/react/src/modules/tpm/TPMIndex.js +++ b/public/react/src/modules/tpm/TPMIndex.js @@ -207,6 +207,7 @@ class TPMIndex extends Component { propaedeutics:response.data.propaedeutics, status: response.data.shixun_status, secret_repository: response.data.secret_repository, + public:response.data.public, is_jupyter:response.data.is_jupyter=== undefined||response.data.is_jupyter===null?false:response.data.is_jupyter, }); @@ -295,10 +296,6 @@ class TPMIndex extends Component { // this.getnavdatas() } - // componentDidUpdate=()=>{ - // this.getnavdatas() - // } - setLoadingContent = (isLoadingContent) => { this.setState({ loadingContent: isLoadingContent }) } @@ -307,9 +304,6 @@ class TPMIndex extends Component { getnavdatas=()=>{ let selectedKeys; const {location} = this.props; - - console.log(location.pathname) - if(location.pathname.indexOf('/challenges')!=-1){ selectedKeys="1" }else if(location.pathname.indexOf('/propaedeutics')!=-1){ From 8fb90e6e20dca4f7d4176d5202c4f564045c2a6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=98=8E?= <775174143@qq.com> Date: Thu, 19 Dec 2019 18:56:56 +0800 Subject: [PATCH 21/39] =?UTF-8?q?=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/react/src/App.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/public/react/src/App.js b/public/react/src/App.js index 07c68e5e0..07fd13e49 100644 --- a/public/react/src/App.js +++ b/public/react/src/App.js @@ -71,11 +71,7 @@ const Otherlogin=Loadable({ loader: () => import('./modules/login/Otherlogin'), loading: Loading, }) -// 学院统计 -const College = Loadable({ - loader: () => import('./college/College'), - loading: Loading -}) + const Otherloginstart=Loadable({ loader: () => import('./modules/login/Otherloginstart'), From ae415cf38249725235db370da0eb3d593ad1d7ce Mon Sep 17 00:00:00 2001 From: daiao <358551898@qq.com> Date: Thu, 19 Dec 2019 19:29:54 +0800 Subject: [PATCH 22/39] 1 --- app/controllers/hacks_controller.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/controllers/hacks_controller.rb b/app/controllers/hacks_controller.rb index cab952a04..dbddd9105 100644 --- a/app/controllers/hacks_controller.rb +++ b/app/controllers/hacks_controller.rb @@ -12,6 +12,7 @@ class HacksController < ApplicationController user_hack = @hack.hack_user_lastest_codes.mine(current_user.id) identifier = if user_hack.present? + logger.info("#####user_hack_id:#{user_hack.id}") user_hack.identifier else user_identifier = generate_identifier HackUserLastestCode, 12 From 992045a5cffc9571f7d311d2b86cd56cd2ef607c Mon Sep 17 00:00:00 2001 From: daiao <358551898@qq.com> Date: Thu, 19 Dec 2019 19:34:54 +0800 Subject: [PATCH 23/39] 1 --- app/models/hack_user_lastest_code.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/hack_user_lastest_code.rb b/app/models/hack_user_lastest_code.rb index b4a707603..830f16dde 100644 --- a/app/models/hack_user_lastest_code.rb +++ b/app/models/hack_user_lastest_code.rb @@ -8,7 +8,7 @@ class HackUserLastestCode < ApplicationRecord belongs_to :user has_many :hack_user_codes, dependent: :destroy has_one :hack_user_debug - scope :mine, ->(author_id){ find_by(user_id: author_id) } + scope :mine, ->(author_id){ where(user_id: author_id).first } scope :mine_hack, ->(author_id){ where(user_id: author_id) } scope :passed, -> {where(status: 1)} From 0074b6d183e5b3a293f341b9ad73196bf79e947e Mon Sep 17 00:00:00 2001 From: daiao <358551898@qq.com> Date: Thu, 19 Dec 2019 19:36:18 +0800 Subject: [PATCH 24/39] 1 --- app/controllers/hacks_controller.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/controllers/hacks_controller.rb b/app/controllers/hacks_controller.rb index dbddd9105..a2ca85f34 100644 --- a/app/controllers/hacks_controller.rb +++ b/app/controllers/hacks_controller.rb @@ -10,6 +10,7 @@ class HacksController < ApplicationController # 未发布的编程题,只能作者、或管理员访问 start_hack_auth user_hack = @hack.hack_user_lastest_codes.mine(current_user.id) + logger.info("#user_hack: #{user_hack}") identifier = if user_hack.present? logger.info("#####user_hack_id:#{user_hack.id}") From a0deef9d09a42d4388a0ba8340e43b5bf2156603 Mon Sep 17 00:00:00 2001 From: daiao <358551898@qq.com> Date: Thu, 19 Dec 2019 19:38:05 +0800 Subject: [PATCH 25/39] 1 --- app/controllers/hacks_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/hacks_controller.rb b/app/controllers/hacks_controller.rb index a2ca85f34..b7f6a30a2 100644 --- a/app/controllers/hacks_controller.rb +++ b/app/controllers/hacks_controller.rb @@ -9,7 +9,7 @@ class HacksController < ApplicationController def start # 未发布的编程题,只能作者、或管理员访问 start_hack_auth - user_hack = @hack.hack_user_lastest_codes.mine(current_user.id) + user_hack = @hack.hack_user_lastest_codes.where(user_id: current_user.id).first logger.info("#user_hack: #{user_hack}") identifier = if user_hack.present? From b7db555654fa0f7122c23e950c4396ca0e90cac8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=98=8E?= <775174143@qq.com> Date: Thu, 19 Dec 2019 20:08:59 +0800 Subject: [PATCH 26/39] =?UTF-8?q?=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tpm/shixunchild/Challenges/Challenges.js | 23 +++++++++-- .../Challenges/Challengesjupyter.js | 39 ++++++++++++++----- .../Collaborators/Collaborators.js | 2 +- 3 files changed, 50 insertions(+), 14 deletions(-) diff --git a/public/react/src/modules/tpm/shixunchild/Challenges/Challenges.js b/public/react/src/modules/tpm/shixunchild/Challenges/Challenges.js index e7b7ef261..0480c208a 100644 --- a/public/react/src/modules/tpm/shixunchild/Challenges/Challenges.js +++ b/public/react/src/modules/tpm/shixunchild/Challenges/Challenges.js @@ -53,6 +53,13 @@ class Challenges extends Component { ChallengesDataList: response.data, sumidtype: false, }); + + if(response.data.description=== ""||response.data.description===null||response.data.description===undefined){ + this.setState({ + isopentitletype:"Less", + }) + } + } } }).catch((error) => { @@ -72,7 +79,7 @@ class Challenges extends Component { let box=document.getElementById("shixunchallengesid"); if(box){ boxoffsetHeigh=box.offsetHeight - if(boxoffsetHeigh<260){ + if(boxoffsetHeigh<300){ this.setState({ isopentitletype:"Less", boxoffsetHeigh:boxoffsetHeigh @@ -338,6 +345,7 @@ class Challenges extends Component { } let id = this.props.match.params.shixunId; const antIcon = <Icon type="loading" style={{ fontSize: 24 }} spin />; + return ( <React.Fragment> {AccountProfiletype===true?<AccountProfile @@ -411,7 +419,7 @@ class Challenges extends Component { { ` #shixunchallengesid{ - max-height: 260px; + max-height: 300px; overflow: hidden; } ` @@ -431,11 +439,18 @@ class Challenges extends Component { <div className="justify break_full_word new_li " id="challenge_editorMd_description"> - <p id="ReactMarkdown" style={{overflow:'hidden'}}> + {ChallengesDataList === undefined || ChallengesDataList&&ChallengesDataList.description=== ""||ChallengesDataList&&ChallengesDataList.description===null||ChallengesDataList&&ChallengesDataList.description===undefined? + <div className="edu-tab-con-box clearfix edu-txt-center"> + {this.props.identity < 5?<img className="newedu-nodata-img mb20" + src={getImageUrl("images/educoder/shixunnodata.png")} />:<img className="edu-nodata-img mb20" + src={getImageUrl("images/educoder/nodata.png")} />} + <p className="edu-nodata-p mb80">暂时还没有相关数据哦!</p> + </div> + :<p id="ReactMarkdown" style={{overflow:'hidden'}}> {ChallengesDataList === undefined ? "" :ChallengesDataList&&ChallengesDataList.description===null?"": <div className={"markdown-body"} dangerouslySetInnerHTML={{__html: markdownToHTML(ChallengesDataList.description).replace(/▁/g,"▁▁▁")}}></div> } - </p> + </p>} </div> </div> diff --git a/public/react/src/modules/tpm/shixunchild/Challenges/Challengesjupyter.js b/public/react/src/modules/tpm/shixunchild/Challenges/Challengesjupyter.js index fcdbed408..c8cbc2fbc 100644 --- a/public/react/src/modules/tpm/shixunchild/Challenges/Challengesjupyter.js +++ b/public/react/src/modules/tpm/shixunchild/Challenges/Challengesjupyter.js @@ -1,6 +1,6 @@ import React, { Component } from 'react'; import { Link } from "react-router-dom"; -import { markdownToHTML, configShareForCustom} from 'educoder' +import { markdownToHTML, configShareForCustom,getImageUrl} from 'educoder' import { Divider, Tooltip } from 'antd'; import LoadingSpin from '../../../../common/LoadingSpin'; import 'antd/lib/pagination/style/index.css'; @@ -23,7 +23,8 @@ class Challengesjupyter extends Component { booljupyterurls:false, loading:false, boxoffsetHeigh:0, - opentitletype:true + opentitletype:true, + isopentitletype:"Less", } } @@ -41,6 +42,11 @@ class Challengesjupyter extends Component { ChallengesDataList: response.data, sumidtype: false, }); + if(response.data.description=== ""||response.data.description===null||response.data.description===undefined){ + this.setState({ + isopentitletype:"Less", + }) + } } } }).catch((error) => { @@ -55,13 +61,15 @@ class Challengesjupyter extends Component { let box=document.getElementById("shixunchallengesid"); if(box){ boxoffsetHeigh=box.offsetHeight - if(boxoffsetHeigh<260){ + if(boxoffsetHeigh<300){ this.setState({ - opentitletype:false, + isopentitletype:"Less", boxoffsetHeigh:boxoffsetHeigh }) }else{ this.setState({ + isopentitletype:"greater", + opentitletype:true, boxoffsetHeigh:boxoffsetHeigh }) } @@ -229,7 +237,7 @@ class Challengesjupyter extends Component { { ` #shixunchallengesid{ - max-height: 260px; + max-height: 300px; overflow: hidden; } ` @@ -239,9 +247,22 @@ class Challengesjupyter extends Component { <div className={"pd20"} id={"shixunchallengesid"}> <p id="ReactMarkdown" style={{overflow:'hidden'}}> - {ChallengesDataList === undefined ? "" :ChallengesDataList&&ChallengesDataList.description===null?"": - <div className={"markdown-body"} dangerouslySetInnerHTML={{__html: markdownToHTML(ChallengesDataList.description).replace(/▁/g,"▁▁▁")}}></div> - } + {/*{ChallengesDataList === undefined ? "" :ChallengesDataList&&ChallengesDataList.description===null?"":*/} + {/* <div className={"markdown-body"} dangerouslySetInnerHTML={{__html: markdownToHTML(ChallengesDataList.description).replace(/▁/g,"▁▁▁")}}></div>*/} + {/*}*/} + + {ChallengesDataList === undefined || ChallengesDataList&&ChallengesDataList.description=== ""||ChallengesDataList&&ChallengesDataList.description===null||ChallengesDataList&&ChallengesDataList.description===undefined? + <div className="edu-tab-con-box clearfix edu-txt-center"> + {this.props.identity < 5?<img className="newedu-nodata-img mb20" + src={getImageUrl("images/educoder/shixunnodata.png")} />:<img className="edu-nodata-img mb20" + src={getImageUrl("images/educoder/nodata.png")} />} + <p className="edu-nodata-p mb80">暂时还没有相关数据哦!</p> + </div> + :<p id="ReactMarkdown" style={{overflow:'hidden'}}> + {ChallengesDataList === undefined ? "" :ChallengesDataList&&ChallengesDataList.description===null?"": + <div className={"markdown-body"} dangerouslySetInnerHTML={{__html: markdownToHTML(ChallengesDataList.description).replace(/▁/g,"▁▁▁")}}></div> + } + </p>} </p> { booljupyterurls===true? @@ -259,7 +280,7 @@ class Challengesjupyter extends Component { } </div> - {this.state.opentitletype===true?<Divider dashed={true} onClick={()=>this.opentitle()} className={"pointer Breadcrumbfont color-grey-9 "}> + {this.state.isopentitletype==="Less"?"":this.state.opentitletype===true?<Divider dashed={true} onClick={()=>this.opentitle()} className={"pointer Breadcrumbfont color-grey-9 "}> <a className={"font-14 color-grey-9"}>阅读全文 <i className={"iconfont icon-jiantou9 font-14"}></i></a> </Divider>:<Divider dashed={true} onClick={()=>this.opentitle()} className={"pointer Breadcrumbfont color-grey-9 "}> <a className={"font-14 color-grey-9"}>收起全文 <i className={"iconfont icon-changyongtubiao-xianxingdaochu-zhuanqu- font-14"}></i></a> diff --git a/public/react/src/modules/tpm/shixunchild/Collaborators/Collaborators.js b/public/react/src/modules/tpm/shixunchild/Collaborators/Collaborators.js index 17b083cf7..9799d060c 100644 --- a/public/react/src/modules/tpm/shixunchild/Collaborators/Collaborators.js +++ b/public/react/src/modules/tpm/shixunchild/Collaborators/Collaborators.js @@ -656,7 +656,7 @@ class Collaborators extends Component { <a href={item.user.user_url} target="_blank" className="mr20 fl edu-position"> <img alt="用户头像" className="radius" height="48" src={getImageUrl("images/" + item.user.image_url)} width="48"/> - <span className={item && item.user && item.user.shixun_manager === true&&this.props.power === true ? "ml20 yslusercjz newyslusercjz" : "none "} + <span className={item && item.user && item.user.shixun_manager === true? "ml20 yslusercjz newyslusercjz" : "none "} // style={{display: this.props.power === false ? "none" : "inline-block"}} > <p className="yslusercjztest newyslusercjztest">{item.user.shixun_manager === true ? "创建者" : ""}</p></span> From e6a0239c2970eb3c31c830ed0de4bbe14aa84a0c Mon Sep 17 00:00:00 2001 From: tangjiang <465264938@qq.com> Date: Thu, 19 Dec 2019 20:11:12 +0800 Subject: [PATCH 27/39] update oj --- .../components/controlSetting/index.js | 20 ++++++++++++------- .../components/monacoSetting/index.js | 4 ++-- .../components/myMonacoEditor/index.js | 4 ++-- .../newOrEditTask/rightpane/index.scss | 3 ++- .../modules/developer/studentStudy/index.js | 9 +++++++-- .../developer/studentStudy/rightpane/index.js | 9 +++++++-- public/react/src/redux/actions/common.js | 4 ++-- public/react/src/redux/actions/index.js | 4 ++-- .../src/redux/reducers/ojForUserReducer.js | 9 +++++++-- 9 files changed, 44 insertions(+), 22 deletions(-) diff --git a/public/react/src/modules/developer/components/controlSetting/index.js b/public/react/src/modules/developer/components/controlSetting/index.js index b5c9222ef..1d4d7834c 100644 --- a/public/react/src/modules/developer/components/controlSetting/index.js +++ b/public/react/src/modules/developer/components/controlSetting/index.js @@ -4,10 +4,10 @@ * @Github: * @Date: 2019-11-27 16:02:36 * @LastEditors: tangjiang - * @LastEditTime: 2019-12-19 10:47:44 + * @LastEditTime: 2019-12-19 19:47:32 */ import './index.scss'; -import React, { useState, useRef } from 'react'; +import React, { useState, useRef, useEffect } from 'react'; import { Tabs, Button, Icon } from 'antd'; import { connect } from 'react-redux'; import InitTabCtx from '../initTabCtx'; @@ -23,10 +23,11 @@ const ControlSetting = (props) => { submitLoading, identifier, excuteState, + showOrHideControl, commitRecordDetail, changeLoadingState, changeSubmitLoadingStatus, - showOrHideControl, + changeShowOrHideControl, // debuggerCode, // startDebuggerCode, // 外部存入 onDebuggerCode, @@ -44,10 +45,14 @@ const ControlSetting = (props) => { setDefaultActiveKey(key); } + useEffect(() => { + setShowTextResult(props.showOrHideControl); + }, [props]); + // 显示/隐藏tab const handleShowControl = () => { setShowTextResult(!showTextResult); - showOrHideControl(!showTextResult); + changeShowOrHideControl(!showTextResult); } // 调试代码 @@ -55,7 +60,7 @@ const ControlSetting = (props) => { // console.log(formRef.current.handleTestCodeFormSubmit); // 调出控制台界面 setShowTextResult(true); - showOrHideControl(true); + changeShowOrHideControl(true); formRef.current.handleTestCodeFormSubmit(() => { setDefaultActiveKey('2'); }); @@ -131,19 +136,20 @@ const ControlSetting = (props) => { const mapStateToProps = (state) => { const {commonReducer, ojForUserReducer} = state; - const {loading, excuteState, submitLoading } = commonReducer; + const {loading, excuteState, submitLoading, showOrHideControl } = commonReducer; const { commitRecordDetail } = ojForUserReducer; return { loading, submitLoading, excuteState, + showOrHideControl, // identifier: user_program_identifier, commitRecordDetail // 提交详情 }; }; // changeSubmitLoadingStatus const mapDispatchToProps = (dispatch) => ({ - showOrHideControl: (flag) => dispatch(actions.showOrHideControl(flag)), + changeShowOrHideControl: (flag) => dispatch(actions.changeShowOrHideControl(flag)), changeLoadingState: (flag) => dispatch(actions.changeLoadingState(flag)), changeSubmitLoadingStatus: (flag) => dispatch(actions.changeSubmitLoadingStatus(flag)), debuggerCode: (identifier, values) => dispatch(actions.debuggerCode(identifier, values)), diff --git a/public/react/src/modules/developer/components/monacoSetting/index.js b/public/react/src/modules/developer/components/monacoSetting/index.js index c1215f9af..669439577 100644 --- a/public/react/src/modules/developer/components/monacoSetting/index.js +++ b/public/react/src/modules/developer/components/monacoSetting/index.js @@ -4,11 +4,11 @@ * @Github: * @Date: 2019-11-25 17:50:33 * @LastEditors: tangjiang - * @LastEditTime: 2019-12-19 15:26:46 + * @LastEditTime: 2019-12-19 19:32:08 */ import React, { useState } from 'react'; import { fromStore, toStore } from 'educoder'; -import { Icon } from 'antd'; +// import { Icon } from 'antd'; // import { Select } from 'antd'; // const { Option } = Select; const SettingDrawer = (props) => { diff --git a/public/react/src/modules/developer/components/myMonacoEditor/index.js b/public/react/src/modules/developer/components/myMonacoEditor/index.js index df3c2b5e3..948d5a4f5 100644 --- a/public/react/src/modules/developer/components/myMonacoEditor/index.js +++ b/public/react/src/modules/developer/components/myMonacoEditor/index.js @@ -4,7 +4,7 @@ * @Github: * @Date: 2019-11-27 15:02:52 * @LastEditors: tangjiang - * @LastEditTime: 2019-12-19 17:52:31 + * @LastEditTime: 2019-12-19 19:36:24 */ import './index.scss'; import React, { useState, useRef, useEffect } from 'react'; @@ -146,7 +146,7 @@ function MyMonacoEditor (props, ref) { > <Icon type="bell" /> </Badge> - <span onClick={handleRestoreCode} className="flex_normal">{renderRestore}</span> + <span onClick={handleRestoreCode} className="flex_normal" style={{ display: identifier ? 'inline-block' : 'none'}}>{renderRestore}</span> <MyIcon className='code-icon' type="iconshezhi" onClick={handleShowDrawer}/> </div> <MonacoEditor diff --git a/public/react/src/modules/developer/newOrEditTask/rightpane/index.scss b/public/react/src/modules/developer/newOrEditTask/rightpane/index.scss index ea2f37c20..9c472b641 100644 --- a/public/react/src/modules/developer/newOrEditTask/rightpane/index.scss +++ b/public/react/src/modules/developer/newOrEditTask/rightpane/index.scss @@ -11,7 +11,8 @@ align-items: center; justify-content: space-between; // padding: 0 30px; - background: #000; + // background: #000; + background: rgba(18,28,36,1); color: #fff; } .code-title, diff --git a/public/react/src/modules/developer/studentStudy/index.js b/public/react/src/modules/developer/studentStudy/index.js index 1db9f7f28..15c87e64c 100644 --- a/public/react/src/modules/developer/studentStudy/index.js +++ b/public/react/src/modules/developer/studentStudy/index.js @@ -4,7 +4,7 @@ * @Github: * @Date: 2019-11-23 10:53:19 * @LastEditors: tangjiang - * @LastEditTime: 2019-12-19 17:51:19 + * @LastEditTime: 2019-12-19 19:48:20 */ import './index.scss'; import React, { useEffect, useState } from 'react'; @@ -29,7 +29,8 @@ function StudentStudy (props) { userInfo, hack_identifier, // user_program_identifier, - restoreInitialCode + restoreInitialCode, + changeShowOrHideControl } = props; const { @@ -88,11 +89,14 @@ function StudentStudy (props) { // 处理编辑 const handleClickEditor = () => { + changeShowOrHideControl(false); props.saveEditorCodeForDetail(); props.history.push(`/problems/${_hack_id}/edit`); } // 处理退出 const handleClickQuit = () => { + // 将控制台关闭 + changeShowOrHideControl(false); props.saveEditorCodeForDetail(); props.history.push('/problems'); } @@ -164,6 +168,7 @@ const mapDispatchToProps = (dispatch) => ({ saveEditorCodeForDetail: (code) => dispatch(actions.saveEditorCodeForDetail(code)), // 恢复初始代码 restoreInitialCode: (identifier, msg) => dispatch(actions.restoreInitialCode(identifier, msg)), + changeShowOrHideControl: (flag) => dispatch(actions.changeShowOrHideControl(flag)) }); export default withRouter(connect( diff --git a/public/react/src/modules/developer/studentStudy/rightpane/index.js b/public/react/src/modules/developer/studentStudy/rightpane/index.js index 5661ea32e..af46d0aef 100644 --- a/public/react/src/modules/developer/studentStudy/rightpane/index.js +++ b/public/react/src/modules/developer/studentStudy/rightpane/index.js @@ -4,7 +4,7 @@ * @Github: * @Date: 2019-11-27 14:59:51 * @LastEditors: tangjiang - * @LastEditTime: 2019-12-19 15:06:49 + * @LastEditTime: 2019-12-19 19:13:05 */ import React, { useState, useEffect } from 'react'; import {connect} from 'react-redux'; @@ -32,6 +32,7 @@ const RightPane = (props) => { const [editorCode, setEditorCode] = useState(''); + let initFlag = true; useEffect(() => { if (editor_code) { setEditorCode(editor_code); @@ -51,8 +52,12 @@ const RightPane = (props) => { // 代码块内容变化时 const handleCodeChange = (code) => { // 保存用户提交的代码块 - // console.log(code); setEditorCode(code); + // 第一次回填代码内容时不更新; + if (initFlag) { + initFlag = false; + return; + } if (!timer) { timer = setInterval(() => { clearInterval(timer); diff --git a/public/react/src/redux/actions/common.js b/public/react/src/redux/actions/common.js index bcd451481..b95d2d2bb 100644 --- a/public/react/src/redux/actions/common.js +++ b/public/react/src/redux/actions/common.js @@ -4,12 +4,12 @@ * @Github: * @Date: 2019-11-27 16:30:50 * @LastEditors: tangjiang - * @LastEditTime: 2019-11-28 21:15:34 + * @LastEditTime: 2019-12-19 19:42:10 */ import types from "./actionTypes"; // 切换控制台显示与隐藏 -export const showOrHideControl = (flag) => { +export const changeShowOrHideControl = (flag) => { return { type: types.SHOW_OR_HIDE_CONTROL, payload: flag diff --git a/public/react/src/redux/actions/index.js b/public/react/src/redux/actions/index.js index ad33061ba..b42c4c2b6 100644 --- a/public/react/src/redux/actions/index.js +++ b/public/react/src/redux/actions/index.js @@ -52,7 +52,7 @@ import { } from './ojForUser'; import { - showOrHideControl, + changeShowOrHideControl, changeLoadingState, changeSubmitLoadingStatus, changePublishLoadingStatus, @@ -97,7 +97,7 @@ export default { testCaseOutputChange, debuggerCode, startProgramQuestion, - showOrHideControl, + changeShowOrHideControl, changeLoadingState, getUserCommitRecord, getUserCommitRecordDetail, diff --git a/public/react/src/redux/reducers/ojForUserReducer.js b/public/react/src/redux/reducers/ojForUserReducer.js index 60e7e6fd1..0c7594dd2 100644 --- a/public/react/src/redux/reducers/ojForUserReducer.js +++ b/public/react/src/redux/reducers/ojForUserReducer.js @@ -4,7 +4,7 @@ * @Github: * @Date: 2019-11-27 13:41:48 * @LastEditors: tangjiang - * @LastEditTime: 2019-12-19 14:49:03 + * @LastEditTime: 2019-12-19 20:10:39 */ import types from "../actions/actionTypes"; import { Base64 } from 'js-base64'; @@ -38,7 +38,12 @@ const ojForUserReducer = (state = initialState, action) => { const { hack, test_case } = action.payload; const { code }= hack; let tempCode = Base64.decode(code) - let tempDesc = JSON.parse(hack.description); + let tempDesc; + try { + tempDesc = JSON.parse(hack.description); + } catch (error) { + tempDesc = hack.description; + } Object.assign(hack, {code: tempCode, description: tempDesc}); return { ...state, From 1cdd29cfd29e1afac3582e38e4e5a70420a7e89c Mon Sep 17 00:00:00 2001 From: daiao <358551898@qq.com> Date: Thu, 19 Dec 2019 20:20:46 +0800 Subject: [PATCH 28/39] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=E9=95=BF=E5=BA=A6=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../20191219120819_modify_description_for_hacks.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 db/migrate/20191219120819_modify_description_for_hacks.rb diff --git a/db/migrate/20191219120819_modify_description_for_hacks.rb b/db/migrate/20191219120819_modify_description_for_hacks.rb new file mode 100644 index 000000000..3cc45fd5d --- /dev/null +++ b/db/migrate/20191219120819_modify_description_for_hacks.rb @@ -0,0 +1,10 @@ +class ModifyDescriptionForHacks < ActiveRecord::Migration[5.2] + def change + change_column :hacks, :description, :longtext + change_column :hack_codes, :code, :longtext + change_column :hack_user_lastest_codes, :code, :longtext + change_column :hack_user_codes, :code, :longtext + change_column :hack_user_debugs, :code, :longtext + + end +end From e176abc4bbc759ad634aa409ec03f7f60ed01555 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=98=8E?= <775174143@qq.com> Date: Thu, 19 Dec 2019 20:42:41 +0800 Subject: [PATCH 29/39] =?UTF-8?q?=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/modules/tpm/shixunchild/Challenges/Challenges.js | 4 ++-- .../modules/tpm/shixunchild/Challenges/Challengesjupyter.js | 6 +++--- .../modules/tpm/shixunchild/Collaborators/Collaborators.js | 3 ++- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/public/react/src/modules/tpm/shixunchild/Challenges/Challenges.js b/public/react/src/modules/tpm/shixunchild/Challenges/Challenges.js index 0480c208a..8890efbd2 100644 --- a/public/react/src/modules/tpm/shixunchild/Challenges/Challenges.js +++ b/public/react/src/modules/tpm/shixunchild/Challenges/Challenges.js @@ -407,10 +407,10 @@ class Challenges extends Component { <span className="font-16 fl">简介</span> {this.props.identity < 5 && ChallengesDataList&&ChallengesDataList.shixun_status < 3 ? - <Link to={"/shixuns/" + id + "/settings"} className="fr color-blue font-14"> + <a href={"/shixuns/" + id + "/settings"} className="fr color-blue font-14"> {/*<img src={getImageUrl("images/educoder/icon/edit.svg")} className="fl mt3 ml2" />*/} 编辑 - </Link>:""} + </a>:""} {this.props.user && this.props.user.main_site === true ? this.props.identity < 5?<a className="fr font-14 color-blue mr20" href="/forums/2943" target="_blank">实训制作指南</a> : "":""} diff --git a/public/react/src/modules/tpm/shixunchild/Challenges/Challengesjupyter.js b/public/react/src/modules/tpm/shixunchild/Challenges/Challengesjupyter.js index c8cbc2fbc..e04ad17c9 100644 --- a/public/react/src/modules/tpm/shixunchild/Challenges/Challengesjupyter.js +++ b/public/react/src/modules/tpm/shixunchild/Challenges/Challengesjupyter.js @@ -227,10 +227,10 @@ class Challengesjupyter extends Component { <div className={"shixunjianjie"}> <span className="font-16 fl">简介</span> <Tooltip placement="bottom" title={"编辑"}> - <Link style={{ display: this.props.identity < 5 && ChallengesDataList&&ChallengesDataList.shixun_status < 3 ? "block" : 'none' }} - to={"/shixuns/" + id + "/settings?edit=1"} className="fr color-blue font-14"> + <a style={{ display: this.props.identity < 5 && ChallengesDataList&&ChallengesDataList.shixun_status < 3 ? "block" : 'none' }} + href={"/shixuns/" + id + "/settings?edit=1"} className="fr color-blue font-14"> 编辑 - </Link> + </a> </Tooltip> </div> {this.state.opentitletype===true?<style> diff --git a/public/react/src/modules/tpm/shixunchild/Collaborators/Collaborators.js b/public/react/src/modules/tpm/shixunchild/Collaborators/Collaborators.js index 9799d060c..a5e055e41 100644 --- a/public/react/src/modules/tpm/shixunchild/Collaborators/Collaborators.js +++ b/public/react/src/modules/tpm/shixunchild/Collaborators/Collaborators.js @@ -330,6 +330,7 @@ class Collaborators extends Component { }); this.updatacomponentDiddata(); this.props.showNotification(response.data.message); + // window.location.reload(); }).catch((error) => { console.log(error) }); @@ -530,7 +531,7 @@ class Collaborators extends Component { { Collaboratorslist.length === 0 ? "" : Collaboratorslist.map((item, key) => { return ( - <Radio key={key} style={radioStyle} value={item.user_id} + <Radio key={key} style={radioStyle} value={item.user_id} defaultChecked={false} onClick={() => this.addadminredio(item.user_id)}>{item.name}</Radio> ) }) From b8275eb7fc1025a149a607b8a06b51eb9dd53eea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=98=8E?= <775174143@qq.com> Date: Thu, 19 Dec 2019 20:58:23 +0800 Subject: [PATCH 30/39] =?UTF-8?q?=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/react/src/modules/tpm/TPMBanner.js | 56 ++++++++++++------- .../tpm/TPMsettings/Shixuninformation.js | 11 +++- .../tpm/shixunchild/Challenges/Challenges.js | 2 +- 3 files changed, 45 insertions(+), 24 deletions(-) diff --git a/public/react/src/modules/tpm/TPMBanner.js b/public/react/src/modules/tpm/TPMBanner.js index 77b82c6c6..da48a5b19 100644 --- a/public/react/src/modules/tpm/TPMBanner.js +++ b/public/react/src/modules/tpm/TPMBanner.js @@ -109,29 +109,45 @@ class TPMBanner extends Component { if (prevProps != this.props) { let shixunopenprocess=window.localStorage.shixunopenprocess; let openopenpublictype=window.localStorage.openopenpublictype; - if(this.props.shixunsDetails&&this.props.shixunsDetails.shixun_status === 0 && this.props.identity < 5){ - if(shixunopenprocess===undefined||shixunopenprocess===false){ - this.setState({ - openknow:true - }) - }else{ - this.setState({ - openknow:false - }) + if(this.props.status===0&&this.props.openknows===false){ + + if(this.props.shixunsDetails&&this.props.shixunsDetails.shixun_status === 0 && this.props.identity < 5){ + if(shixunopenprocess===undefined||shixunopenprocess===false){ + this.setState({ + openknow:true + }) + }else{ + this.setState({ + openknow:false + }) + } } + }else{ + this.setState({ + openknow:false + }) } - if(this.props.shixunsDetails&&this.props.shixunsDetails.shixun_status === 2 && this.props.shixunsDetails&&this.props.shixunsDetails.public===0 && this.props.identity < 5){ - if(openopenpublictype===undefined||openopenpublictype===false){ - this.setState({ - openshowpublictype:true - }) - }else{ - this.setState({ - openshowpublictype:false - }) + + + if(this.props.public===0&&this.props.status>1&&this.props.openknows===false){ + if(this.props.shixunsDetails&&this.props.shixunsDetails.shixun_status === 2 && this.props.shixunsDetails&&this.props.shixunsDetails.public===0 && this.props.identity < 5){ + if(openopenpublictype===undefined||openopenpublictype===false){ + this.setState({ + openshowpublictype:true + }) + }else{ + this.setState({ + openshowpublictype:false + }) + } } + }else{ + this.setState({ + openshowpublictype:false + }) } + } } @@ -779,8 +795,8 @@ class TPMBanner extends Component { }; // // console.log(this.props.shixunsDetails&&this.props.shixunsDetails.is_jupyter) - console.log(this.props) - console.log(this.state) + // console.log(this.props) + // console.log(this.state) return ( shixunsDetails === undefined ? "" : diff --git a/public/react/src/modules/tpm/TPMsettings/Shixuninformation.js b/public/react/src/modules/tpm/TPMsettings/Shixuninformation.js index 75ed88852..66e1da8dd 100644 --- a/public/react/src/modules/tpm/TPMsettings/Shixuninformation.js +++ b/public/react/src/modules/tpm/TPMsettings/Shixuninformation.js @@ -50,10 +50,15 @@ class Shixuninformation extends Component { } componentDidMount() { - let anchorElement = document.getElementById("newcourseContentMD"); - if(anchorElement){ - this.scrollToAnchor("newcourseContentMD"); + let query=this.props.location.search + const types = query.split('?edit=') + if(types[1]==="1"){ + let anchorElement = document.getElementById("newcourseContentMD"); + if(anchorElement){ + this.scrollToAnchor("newcourseContentMD"); + } } + } componentDidUpdate(prevProps, prevState) { diff --git a/public/react/src/modules/tpm/shixunchild/Challenges/Challenges.js b/public/react/src/modules/tpm/shixunchild/Challenges/Challenges.js index 8890efbd2..548e7224a 100644 --- a/public/react/src/modules/tpm/shixunchild/Challenges/Challenges.js +++ b/public/react/src/modules/tpm/shixunchild/Challenges/Challenges.js @@ -407,7 +407,7 @@ class Challenges extends Component { <span className="font-16 fl">简介</span> {this.props.identity < 5 && ChallengesDataList&&ChallengesDataList.shixun_status < 3 ? - <a href={"/shixuns/" + id + "/settings"} className="fr color-blue font-14"> + <a href={"/shixuns/" + id + "/settings?edit=1"} className="fr color-blue font-14"> {/*<img src={getImageUrl("images/educoder/icon/edit.svg")} className="fl mt3 ml2" />*/} 编辑 </a>:""} From 3d47545da8aaf146ced03958fd2c9ef46ebcd151 Mon Sep 17 00:00:00 2001 From: tangjiang <465264938@qq.com> Date: Fri, 20 Dec 2019 09:45:45 +0800 Subject: [PATCH 31/39] update style --- .../components/myMonacoEditor/index.scss | 2 +- .../leftpane/editorTab/AddTestDemo.js | 108 +++++++++--------- .../newOrEditTask/leftpane/editorTab/index.js | 4 +- .../leftpane/editorTab/index.scss | 8 +- .../newOrEditTask/rightpane/index.scss | 2 +- .../modules/developer/recordDetail/index.scss | 2 +- .../modules/developer/split_pane_resizer.scss | 2 +- .../leftpane/commitRecord/index.js | 24 ++-- .../leftpane/commitRecord/index.scss | 2 +- .../studentStudy/leftpane/index.scss | 7 +- .../leftpane/taskDescription/index.js | 4 +- .../modules/tpm/jupyter/leftPane/index.scss | 2 +- 12 files changed, 90 insertions(+), 77 deletions(-) diff --git a/public/react/src/modules/developer/components/myMonacoEditor/index.scss b/public/react/src/modules/developer/components/myMonacoEditor/index.scss index 61689b51e..a9fe17b94 100644 --- a/public/react/src/modules/developer/components/myMonacoEditor/index.scss +++ b/public/react/src/modules/developer/components/myMonacoEditor/index.scss @@ -7,7 +7,7 @@ background-color: rgba(18,28,36,1); color: #fff; height: 56px; - padding: 0 30px; + padding: 0 20px; .flex_strict{ flex: 1; } diff --git a/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/AddTestDemo.js b/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/AddTestDemo.js index 8e7aa70fc..e42004555 100644 --- a/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/AddTestDemo.js +++ b/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/AddTestDemo.js @@ -4,11 +4,11 @@ * @Github: * @Date: 2019-11-21 09:19:38 * @LastEditors: tangjiang - * @LastEditTime: 2019-12-19 17:54:28 + * @LastEditTime: 2019-12-20 09:23:07 */ import './index.scss'; import React, { useState } from 'react'; -import { Collapse, Icon, Input, Form, Button } from 'antd'; +import { Collapse, Icon, Input, Form } from 'antd'; import { connect } from 'react-redux'; import actions from '../../../../../redux/actions'; import { CNotificationHOC} from 'educoder'; @@ -18,14 +18,14 @@ const FormItem = Form.Item; const AddTestDemo = (props) => { const { key, - onSubmitTest, + // onSubmitTest, onDeleteTest, testCase, testCaseValidate, isOpen } = props; - const [isEditor, setIsEditor] = useState(false); // 是否是编辑 + // const [isEditor, setIsEditor] = useState(false); // 是否是编辑 // 删除操作 const handleDeletePanel = (e) => { @@ -73,54 +73,54 @@ const AddTestDemo = (props) => { ) // 取消操作 - const handleReset = (e) => { - e.preventDefault(); - props.form.resetFields(); - } + // const handleReset = (e) => { + // e.preventDefault(); + // props.form.resetFields(); + // } // 保存 - const handleSubmit = (e) => { - e.preventDefault(); - props.form.validateFields((err, values) => { - if (err) { - return; - } - console.log('提交表单: ', values); - onSubmitTest(values); - }); - } + // const handleSubmit = (e) => { + // e.preventDefault(); + // props.form.validateFields((err, values) => { + // if (err) { + // return; + // } + // console.log('提交表单: ', values); + // onSubmitTest(values); + // }); + // } // 编辑后保存 - const handleEditorOrSave = (e) => { - if (!isEditor) { - setIsEditor(true); - } else { - // TODO 调用修改测试用例接口 - setIsEditor(false); // 保存后 设置 false - } - } + // const handleEditorOrSave = (e) => { + // if (!isEditor) { + // setIsEditor(true); + // } else { + // // TODO 调用修改测试用例接口 + // setIsEditor(false); // 保存后 设置 false + // } + // } // 渲染提交按钮 - const renderSubmitBtn = () => { - const { identifier, testCase, loading } = props; - // console.log('========', identifier); - // 1. 新增时,不显示按钮 - if (identifier) { - if (testCase.isAdd) { - return ( - <FormItem style={{ textAlign: 'right' }}> - <Button style={{ marginRight: '20px' }} onClick={handleReset}>取消</Button> - <Button type="primary" onClick={handleSubmit}>保存</Button> - </FormItem> - ); - } else { - return ( - <FormItem style={{ textAlign: 'right' }}> - <Button onClick={handleEditorOrSave} loading={loading}>{isEditor ? '保存' : (loading ? '保存' : '编辑')}</Button> - </FormItem> - ); - } - } - } + // const renderSubmitBtn = () => { + // const { identifier, testCase, loading } = props; + // // console.log('========', identifier); + // // 1. 新增时,不显示按钮 + // if (identifier) { + // if (testCase.isAdd) { + // return ( + // <FormItem style={{ textAlign: 'right' }}> + // <Button style={{ marginRight: '20px' }} onClick={handleReset}>取消</Button> + // <Button type="primary" onClick={handleSubmit}>保存</Button> + // </FormItem> + // ); + // } else { + // return ( + // <FormItem style={{ textAlign: 'right' }}> + // <Button onClick={handleEditorOrSave} loading={loading}>{isEditor ? '保存' : (loading ? '保存' : '编辑')}</Button> + // </FormItem> + // ); + // } + // } + // } /** * 文本输入框可编辑的情况 @@ -128,9 +128,9 @@ const AddTestDemo = (props) => { * 2. isAdd 为 false 且 isEditor 为true 时 * @param {*} testCase */ - const isDisabled = (testCase) => { - return !testCase.isAdd && !isEditor; - }; + // const isDisabled = (testCase) => { + // return !testCase.isAdd && !isEditor; + // }; // const {input = {}, output = {}} = (testCasesValidate[index] = {}); const activePane = { @@ -158,7 +158,8 @@ const AddTestDemo = (props) => { rows={5} value={testCase.input} onChange={handleInputChange} - disabled={isDisabled(testCase)}/> + // disabled={isDisabled(testCase)} + /> </FormItem> <FormItem label={<span className={'label_text'}>输出</span>} @@ -170,9 +171,10 @@ const AddTestDemo = (props) => { rows={5} value={testCase.output} onChange={handleOutputChange} - disabled={isDisabled(testCase)}/> + // disabled={isDisabled(testCase)} + /> </FormItem> - {renderSubmitBtn()} + {/* {renderSubmitBtn()} */} </Form> </Panel> </Collapse> diff --git a/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/index.js b/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/index.js index da31754bd..b1bf28d55 100644 --- a/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/index.js +++ b/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/index.js @@ -4,7 +4,7 @@ * @Github: * @Date: 2019-11-20 10:35:40 * @LastEditors: tangjiang - * @LastEditTime: 2019-12-19 17:23:10 + * @LastEditTime: 2019-12-19 20:16:32 */ import './index.scss'; // import 'katex/dist/katex.css'; @@ -311,7 +311,7 @@ class EditTab extends React.Component { <div style={{ marginTop: '15px'}}> <QuillForEditor style={{ height: '200px', 'overflowY': 'auto' }} - placeholder="init content" + placeholder="请输入描述信息" onContentChange={handleContentChange} options={quillConfig} value={ojForm.description} diff --git a/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/index.scss b/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/index.scss index 17f3eae34..56fa3e306 100644 --- a/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/index.scss +++ b/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/index.scss @@ -48,7 +48,7 @@ .test_demo_title, .test_demo_ctx, .editor_form{ - margin: 0 30px; + margin: 0 20px; .ant-form-explain{ margin-top: 5px; @@ -68,7 +68,7 @@ top: 43px; left: -30px; right: -30px; - padding: 0 30px; + padding: 0 20px; // background: gold; background: rgb(249,249,249); z-index: 1000; @@ -77,5 +77,9 @@ .collapse_area{ margin-bottom: 20px; + + .ant-form-item{ + margin-bottom: 0px; + } } } \ No newline at end of file diff --git a/public/react/src/modules/developer/newOrEditTask/rightpane/index.scss b/public/react/src/modules/developer/newOrEditTask/rightpane/index.scss index 9c472b641..4bec9546e 100644 --- a/public/react/src/modules/developer/newOrEditTask/rightpane/index.scss +++ b/public/react/src/modules/developer/newOrEditTask/rightpane/index.scss @@ -17,7 +17,7 @@ } .code-title, .pane_control_opts{ - padding: 0 30px; + padding: 0 20px; } .code-title{ diff --git a/public/react/src/modules/developer/recordDetail/index.scss b/public/react/src/modules/developer/recordDetail/index.scss index 5c6c78f7e..e52090060 100644 --- a/public/react/src/modules/developer/recordDetail/index.scss +++ b/public/react/src/modules/developer/recordDetail/index.scss @@ -2,7 +2,7 @@ .record_detail_area{ .record_detail_ctx{ - padding: 0 30px; + padding: 0 20px; .detail_ctx_header{ position: relative; height: 56px; diff --git a/public/react/src/modules/developer/split_pane_resizer.scss b/public/react/src/modules/developer/split_pane_resizer.scss index 2898d966c..fc868022d 100644 --- a/public/react/src/modules/developer/split_pane_resizer.scss +++ b/public/react/src/modules/developer/split_pane_resizer.scss @@ -88,7 +88,7 @@ .add_editor_list_area{ background: #fff; - padding: 0 30px; + padding: 0 20px; margin: 0; .add_editor_item{ display: inline-block; diff --git a/public/react/src/modules/developer/studentStudy/leftpane/commitRecord/index.js b/public/react/src/modules/developer/studentStudy/leftpane/commitRecord/index.js index 63d1bd2a3..7fc061765 100644 --- a/public/react/src/modules/developer/studentStudy/leftpane/commitRecord/index.js +++ b/public/react/src/modules/developer/studentStudy/leftpane/commitRecord/index.js @@ -4,7 +4,7 @@ * @Github: * @Date: 2019-11-27 09:49:33 * @LastEditors: tangjiang - * @LastEditTime: 2019-12-05 10:38:49 + * @LastEditTime: 2019-12-20 09:35:00 */ import './index.scss'; import React, { useState, useEffect } from 'react'; @@ -79,6 +79,9 @@ const CommitRecord = (props) => { const [pagination, setPagination] = useState(paginationConfig); const [tableData, setTableData] = useState([]); + + let clipboard; + // const [recordDetail, setRecordDetail] = useState({}); const [renderCtx, setRenderCtx] = useState(() => { return function () { @@ -89,14 +92,14 @@ const CommitRecord = (props) => { const renderRecordDetail = () => { const { id, - error_line, - error_msg, - execute_memory, - execute_time, - input, - output, + // error_line, + // error_msg, + // execute_memory, + // execute_time, + // input, + // output, status, - expected_output + // expected_output } = commitRecordDetail; if (Object.keys(commitRecordDetail).length > 0) { console.log('当前状态====》》》', status); @@ -146,9 +149,12 @@ const CommitRecord = (props) => { setRenderCtx(() => (renderRecordDetail)) }, [commitRecordDetail]); // 复制功能 + useEffect(() => { + if (!clipboard) { + clipboard = new ClipboardJS('.copy_error'); + } if (commitRecordDetail.status !== 0) { - const clipboard = new ClipboardJS('.copy_error'); clipboard.on('success', (e) => { message.success('复制成功'); e.clearSelection(); diff --git a/public/react/src/modules/developer/studentStudy/leftpane/commitRecord/index.scss b/public/react/src/modules/developer/studentStudy/leftpane/commitRecord/index.scss index 596e9abe7..283617445 100644 --- a/public/react/src/modules/developer/studentStudy/leftpane/commitRecord/index.scss +++ b/public/react/src/modules/developer/studentStudy/leftpane/commitRecord/index.scss @@ -1,6 +1,6 @@ .commit_record_area{ // padding: 20px 30px; - padding: 0 30px; + padding: 0 20px; .record_header{ display: flex; // justify-content: space-between; diff --git a/public/react/src/modules/developer/studentStudy/leftpane/index.scss b/public/react/src/modules/developer/studentStudy/leftpane/index.scss index 1582c033f..a48d021f9 100644 --- a/public/react/src/modules/developer/studentStudy/leftpane/index.scss +++ b/public/react/src/modules/developer/studentStudy/leftpane/index.scss @@ -16,7 +16,7 @@ box-sizing: border-box; border-top: 1px solid rgba(244,244,244,1); // background: pink; - padding: 0 30px; + padding: 0 20px; // background-color: rgba(250,250,250,1); background: #fff; @@ -32,7 +32,7 @@ } .commit_record_area{ - padding: 0 30px; + padding: 0 20px; // height: calc(100vh - 178px); // overflow-y: auto; } @@ -40,6 +40,7 @@ .task_desc_area{ height: calc(100vh - 242px); + overflow-y: auto; padding: 0 0 0 15px; } .desc_area_header{ @@ -47,7 +48,7 @@ justify-content: space-between; align-items: center; height: 64px; - padding: 0 30px; + padding: 0 20px; .header_flex{ font-size: 14px; .flex_label{ diff --git a/public/react/src/modules/developer/studentStudy/leftpane/taskDescription/index.js b/public/react/src/modules/developer/studentStudy/leftpane/taskDescription/index.js index 981770b8c..3f4a3d6c0 100644 --- a/public/react/src/modules/developer/studentStudy/leftpane/taskDescription/index.js +++ b/public/react/src/modules/developer/studentStudy/leftpane/taskDescription/index.js @@ -4,7 +4,7 @@ * @Github: * @Date: 2019-11-27 09:49:30 * @LastEditors: tangjiang - * @LastEditTime: 2019-12-19 09:22:52 + * @LastEditTime: 2019-12-20 09:39:35 */ import '../index.scss'; import React from 'react'; @@ -41,7 +41,7 @@ const TaskDescription = (props) => { </p> </div> <div className="task_desc_area"> - <QuillForEditor + <QuillForEditor readOnly={true} value={description} /> diff --git a/public/react/src/modules/tpm/jupyter/leftPane/index.scss b/public/react/src/modules/tpm/jupyter/leftPane/index.scss index 9c95b1aae..352e1c9ab 100644 --- a/public/react/src/modules/tpm/jupyter/leftPane/index.scss +++ b/public/react/src/modules/tpm/jupyter/leftPane/index.scss @@ -6,7 +6,7 @@ line-height: 44px; // background-color: #EEEEEE; background: #fff; - padding: 0 30px; + padding: 0 20px; font-size: 16px; // box-size: border-box; box-sizing: border-box; From 9e3f429b1ead791192887391b708792e16ecb446 Mon Sep 17 00:00:00 2001 From: cxt <853663049@qq.com> Date: Fri, 20 Dec 2019 10:38:15 +0800 Subject: [PATCH 32/39] =?UTF-8?q?=E4=BA=91=E4=B8=8A=E5=AE=9E=E9=AA=8C?= =?UTF-8?q?=E5=AE=A4=E7=9A=84=E5=90=8E=E5=8F=B0=E7=AE=A1=E7=90=86url?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/users/get_navigation_info.json.jbuilder | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/views/users/get_navigation_info.json.jbuilder b/app/views/users/get_navigation_info.json.jbuilder index c507f7ef8..a0f10677c 100644 --- a/app/views/users/get_navigation_info.json.jbuilder +++ b/app/views/users/get_navigation_info.json.jbuilder @@ -41,7 +41,9 @@ json.top do json.old_url @old_domain # 云上实验室管理权限 - json.laboratory_user current_laboratory.laboratory_users.exists?(user_id: @user&.id) || @user&.admin_or_business? + laboratory_user = current_laboratory.laboratory_users.exists?(user_id: @user&.id) || @user&.admin_or_business? + json.laboratory_user laboratory_user + json.laboratory_admin_url laboratory_user ? "/cooperative" : nil end json.down do From a9c3bc81b0b42c68b315032c5bbc18e80f431dfe Mon Sep 17 00:00:00 2001 From: tangjiang <465264938@qq.com> Date: Fri, 20 Dec 2019 10:38:24 +0800 Subject: [PATCH 33/39] update style --- .../modules/developer/recordDetail/index.js | 5 +- public/react/src/redux/actions/ojForUser.js | 187 +++++++++--------- public/react/src/services/ojService.js | 3 +- 3 files changed, 99 insertions(+), 96 deletions(-) diff --git a/public/react/src/modules/developer/recordDetail/index.js b/public/react/src/modules/developer/recordDetail/index.js index 1951b7712..7a3fc13e1 100644 --- a/public/react/src/modules/developer/recordDetail/index.js +++ b/public/react/src/modules/developer/recordDetail/index.js @@ -4,7 +4,7 @@ * @Github: * @Date: 2019-12-04 08:36:21 * @LastEditors: tangjiang - * @LastEditTime: 2019-12-10 18:55:02 + * @LastEditTime: 2019-12-20 10:38:00 */ import './index.scss'; import React, { useState, useEffect } from 'react'; @@ -79,7 +79,7 @@ function RecordDetail (props) { </div> <div className="detail_ctx_status"> <span className="status_label"> - 状态: <span className="status_label_error">{reviewResult[detail.status]}</span> + 状态: <span className={detail.status === 0 ? 'status_label_success' : 'status_label_error'}>{reviewResult[detail.status]}</span> </span> <span className="status_label"> 提交时间: <span className="status_label_sub"> @@ -89,6 +89,7 @@ function RecordDetail (props) { <span className="status_label"> 语言: <span className="status_label_sub">C</span> </span> + {/* <span className> */} </div> <div className="result_error_area"> <ErrorResult detail={detail}/> diff --git a/public/react/src/redux/actions/ojForUser.js b/public/react/src/redux/actions/ojForUser.js index 9cb814d80..994830280 100644 --- a/public/react/src/redux/actions/ojForUser.js +++ b/public/react/src/redux/actions/ojForUser.js @@ -4,7 +4,7 @@ * @Github: * @Date: 2019-11-27 13:42:11 * @LastEditors: tangjiang - * @LastEditTime: 2019-12-19 15:11:56 + * @LastEditTime: 2019-12-20 10:25:42 */ import types from "./actionTypes"; import { Base64 } from 'js-base64'; @@ -171,6 +171,94 @@ export const updateCode = (identifier, inputValue, type) => { } } +// 代码评测 +export const codeEvaluate = (dispatch, identifier, type, time_limit) => { + // 调试代码成功后,调用轮循接口, 注意: 代码执行的时间要小于设置的时间限制 + const intervalTime = 500; + let count = 1; + /** + * @param {*} excuteTime 执行时间 + * @param {*} finalTime 总时间 + * @param {*} count 执行次数 + * @param {*} timer 定时器 + */ + function getCodeSubmit (intervalTime, finalTime, count, timer){ + const excuteTime = (count++) * intervalTime; // 当前执行时间 + fetchCodeSubmit(identifier, { mode: type }).then(res => { + const { status } = res.data; // 评测返回结果 + // 清除定时器条件: 评测通过或者评测时间大于指定时间 + if (+status === 0 || (excuteTime / 1000) > (finalTime + 1)) { + clearInterval(timer); // 清除定时器 + timer = null; + let returnData = null; + if (status === 1) { // 结果没有返回 + returnData = { + error_line: -1, + error_msg: '', + execute_memory: '', + execute_time: finalTime, + input: '', + output: '', + status: 2, + expected_output: '' + }; + } else { // 成功返回结果 + returnData = res.data.data; + } + // 返回评测结果 + dispatch({ + type: types.COMMIT_RECORD_DETAIL, + payload: returnData + }); + if (!type || type === 'debug') { + dispatch({ // 改变 loading 值 + type: types.LOADING_STATUS, + payload: false + }); + // 保存执行状态 + dispatch({ + type: types.TEST_CODE_STATUS, + payload: 'finish' + }); + } else { + // 回滚提交按钮状态 + dispatch({ + type: types.SUBMIT_LOADING_STATUS, + payload: false + }); + // 改变tab值至提交记录(只在提交时才跳转,测评时,切换到代码执行结果就可以了) + dispatch({ + type: types.CHANGE_USER_CODE_TAB, + payload: 'record' + }); + // 重新调用一下提交记录接口 + dispatch(getUserCommitRecord(identifier)); + } + } + }).catch(err => { // 评测异常时 + // 清除定时器 + clearInterval(timer); + timer = null; + // 回滚按钮状态 + if (!type || type === 'debug') { + dispatch({ // 改变 loading 值 + type: types.LOADING_STATUS, + payload: false + }); + } else { // 回滚提交按钮状态 + dispatch({ + type: types.SUBMIT_LOADING_STATUS, + payload: false + }); + } + }); + } + // 开启定时器,调用监听接口 + let timer = setInterval(() => { + getCodeSubmit(intervalTime, time_limit, count++, timer); + }, intervalTime); +} + /** * @description 调试代码 * @param {*} identifier @@ -194,15 +282,6 @@ export const debuggerCode = (identifier,value, type) => { // console.log('调用调试代码成功并返回结果: ', res); const { status } = res; if (status === 200) { - // 调试代码成功后,调用轮循接口, 注意: 代码执行的时间要小于设置的时间限制 - const intervalTime = 500; - let count = 1; - /** - * @param {*} excuteTime 执行时间 - * @param {*} finalTime 总时间 - * @param {*} count 执行次数 - * @param {*} timer 定时器 - */ if (res.data.status === 401) { dispatch({ // 改变 loading 值 type: types.LOADING_STATUS, @@ -210,81 +289,8 @@ export const debuggerCode = (identifier,value, type) => { }); return; }; - function getCodeSubmit (intervalTime, finalTime, count, timer){ - const excuteTime = (count++) * intervalTime; // 当前执行时间 - fetchCodeSubmit(identifier, { mode: type }).then(res => { - const { status } = res.data; // 评测返回结果 - // 清除定时器条件: 评测通过或者评测时间大于指定时间 - if (+status === 0 || (excuteTime / 1000) > (finalTime + 1)) { - clearInterval(timer); // 清除定时器 - timer = null; - let returnData = null; - if (status === 1) { // 结果没有返回 - returnData = { - error_line: -1, - error_msg: '', - execute_memory: '', - execute_time: finalTime, - input: '', - output: '', - status: 2, - expected_output: '' - }; - } else { // 成功返回结果 - returnData = res.data.data; - } - // 返回评测结果 - dispatch({ - type: types.COMMIT_RECORD_DETAIL, - payload: returnData - }); - if (!type || type === 'debug') { - dispatch({ // 改变 loading 值 - type: types.LOADING_STATUS, - payload: false - }); - // 保存执行状态 - dispatch({ - type: types.TEST_CODE_STATUS, - payload: 'finish' - }); - } else { - // 回滚提交按钮状态 - dispatch({ - type: types.SUBMIT_LOADING_STATUS, - payload: false - }); - // 改变tab值至提交记录(只在提交时才跳转,测评时,切换到代码执行结果就可以了) - dispatch({ - type: types.CHANGE_USER_CODE_TAB, - payload: 'record' - }); - // 重新调用一下提交记录接口 - dispatch(getUserCommitRecord(identifier)); - } - } - }).catch(err => { // 评测异常时 - // 清除定时器 - clearInterval(timer); - timer = null; - // 回滚按钮状态 - if (!type || type === 'debug') { - dispatch({ // 改变 loading 值 - type: types.LOADING_STATUS, - payload: false - }); - } else { // 回滚提交按钮状态 - dispatch({ - type: types.SUBMIT_LOADING_STATUS, - payload: false - }); - } - }); - } - // 开启定时器,调用监听接口 - let timer = setInterval(() => { - getCodeSubmit(intervalTime, time_limit, count++, timer); - }, intervalTime); + // 测评 + codeEvaluate(dispatch, identifier, type, time_limit); } }).catch(() => { dispatch({ @@ -362,7 +368,8 @@ export const changeUserCodeTab = (key) => { */ export const submitUserCode = (identifier, inputValue, type) => { return (dispatch, getState) => { - const { userCode, isUpdateCode } = getState().ojForUserReducer; + const { userCode, isUpdateCode, hack: {time_limit = 0} } = getState().ojForUserReducer; + function userCodeSubmit () { fetchUserCodeSubmit(identifier).then(res => { // console.log('用户提交代码成功======》》》》》', res); @@ -374,12 +381,8 @@ export const submitUserCode = (identifier, inputValue, type) => { }); return; }; - // 将编辑代码清空 - dispatch({ - type: types.SAVE_EDITOR_CODE, - payload: '' - }); - dispatch(debuggerCode(identifier, inputValue, type || 'submit')); + // 测评 + codeEvaluate(dispatch, identifier, type, time_limit); } }).catch(() => { dispatch({ diff --git a/public/react/src/services/ojService.js b/public/react/src/services/ojService.js index 373805b73..aeeb212a2 100644 --- a/public/react/src/services/ojService.js +++ b/public/react/src/services/ojService.js @@ -4,11 +4,10 @@ * @Github: * @Date: 2019-11-20 10:55:38 * @LastEditors: tangjiang - * @LastEditTime: 2019-12-17 14:10:37 + * @LastEditTime: 2019-12-20 10:10:53 */ import axios from 'axios'; -import { func } from 'prop-types'; export async function fetchOJList (params) { console.log('传递的参数: ', params); From ecc04b52eab624c4fd334e58dae7d8ce6b412042 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=9E=97?= <904079904@qq.com> Date: Fri, 20 Dec 2019 10:38:56 +0800 Subject: [PATCH 34/39] =?UTF-8?q?=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/react/src/college/College.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/public/react/src/college/College.js b/public/react/src/college/College.js index bc43252b7..fb116429d 100644 --- a/public/react/src/college/College.js +++ b/public/react/src/college/College.js @@ -45,11 +45,13 @@ class College extends Component { align: 'center', className: "edu-txt-center font-14 maxnamewidth340", render: (text, record) => ( - <span className="maxnamewidth340"> + <a className="maxnamewidth340" title={record.teachers} style={{ + color:'#05101A' + }}> { record.teachers } - </span> + </a > ) }, { From 285b896b050466f5c0ede84186cea41a86609a1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=9E=97?= <904079904@qq.com> Date: Fri, 20 Dec 2019 10:44:20 +0800 Subject: [PATCH 35/39] =?UTF-8?q?=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/react/src/modules/tpm/NewHeader.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/react/src/modules/tpm/NewHeader.js b/public/react/src/modules/tpm/NewHeader.js index 06369d3d2..84354369c 100644 --- a/public/react/src/modules/tpm/NewHeader.js +++ b/public/react/src/modules/tpm/NewHeader.js @@ -1218,7 +1218,7 @@ submittojoinclass=(value)=>{ } { this.props.Headertop && this.props.Headertop.laboratory_user && - <li><a href="/cooperative">后台管理</a></li> + <li><a href={this.props.Headertop.laboratory_admin_url}>后台管理</a></li> } <li><a href={`/account/profile`}>账号管理</a></li> From 8bf85007bc52e57d05d03c58557b69a3f1bd1c55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=9E=97?= <904079904@qq.com> Date: Fri, 20 Dec 2019 10:56:32 +0800 Subject: [PATCH 36/39] =?UTF-8?q?=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/react/src/modules/tpm/TPMDataset.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/react/src/modules/tpm/TPMDataset.js b/public/react/src/modules/tpm/TPMDataset.js index 85ce2006e..55cd8c746 100644 --- a/public/react/src/modules/tpm/TPMDataset.js +++ b/public/react/src/modules/tpm/TPMDataset.js @@ -461,7 +461,7 @@ class TPMDataset extends Component { const uploadProps = { width: 600, fileList, - multiple: false, + multiple: true, //multiple 是否支持多选 查重的时候不能多选 不然弹许多框出来 // https://github.com/ant-design/ant-design/issues/15505 // showUploadList={false},然后外部拿到 fileList 数组自行渲染列表。 From 58bdc55b3f766c7c27e515b03ec6c32daf02f601 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=98=8E?= <775174143@qq.com> Date: Fri, 20 Dec 2019 11:27:46 +0800 Subject: [PATCH 37/39] =?UTF-8?q?=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tpm/shixunchild/Challenges/Challenges.js | 105 +++++++++++++----- .../Challenges/Challengesjupyter.js | 80 +++++++++---- 2 files changed, 132 insertions(+), 53 deletions(-) diff --git a/public/react/src/modules/tpm/shixunchild/Challenges/Challenges.js b/public/react/src/modules/tpm/shixunchild/Challenges/Challenges.js index 548e7224a..b1340c0de 100644 --- a/public/react/src/modules/tpm/shixunchild/Challenges/Challenges.js +++ b/public/react/src/modules/tpm/shixunchild/Challenges/Challenges.js @@ -59,7 +59,7 @@ class Challenges extends Component { isopentitletype:"Less", }) } - + this.getjianjiesize() } } }).catch((error) => { @@ -67,31 +67,54 @@ class Challenges extends Component { }); } + getjianjiesize=()=>{ + let {ChallengesDataList}=this.state; + let boxoffsetHeigh; + let box=document.getElementById("shixunchallengesid"); + + if(box){ + boxoffsetHeigh=box.offsetHeight + if(ChallengesDataList === undefined || ChallengesDataList&&ChallengesDataList.description=== ""||ChallengesDataList&&ChallengesDataList.description===null||ChallengesDataList&&ChallengesDataList.description===undefined){ + + }else{ + if(this.state.isopentitletype==="greater"){ + + }else{ + if(boxoffsetHeigh>=300){ + this.setState({ + opentitletype:true, + isopentitletype:"greater", + boxoffsetHeigh:boxoffsetHeigh + }) + }else{ + this.setState({ + isopentitletype:"Less", + boxoffsetHeigh:boxoffsetHeigh + }) + } + } + + } + + } + } + componentDidMount() { - this.ChallengesList() + if(this.state.isopentitletype==="greater"){ + + }else { + this.ChallengesList() + } } componentDidUpdate = (prevProps,prevState) => { //防止陷入无限循环 if(prevState.ChallengesDataList!=this.state.ChallengesDataList){ - let boxoffsetHeigh; - let box=document.getElementById("shixunchallengesid"); - if(box){ - boxoffsetHeigh=box.offsetHeight - if(boxoffsetHeigh<300){ - this.setState({ - isopentitletype:"Less", - boxoffsetHeigh:boxoffsetHeigh - }) - }else{ - this.setState({ - opentitletype:true, - isopentitletype:"greater", - boxoffsetHeigh:boxoffsetHeigh - }) - } - console.log(boxoffsetHeigh) + if(this.state.isopentitletype==="greater"){ + + }else{ + this.getjianjiesize() } } @@ -333,7 +356,6 @@ class Challenges extends Component { opentitle=()=>{ this.setState({ opentitletype:!this.state.opentitletype, - }) } @@ -415,16 +437,7 @@ class Challenges extends Component { this.props.identity < 5?<a className="fr font-14 color-blue mr20" href="/forums/2943" target="_blank">实训制作指南</a> : "":""} </div> - {this.state.opentitletype===true?<style> - { - ` - #shixunchallengesid{ - max-height: 300px; - overflow: hidden; - } - ` - } - </style>:""} + <div> <div className={"pd20"} id={"shixunchallengesid"}> <style> @@ -436,6 +449,38 @@ class Challenges extends Component { ` } </style> + <style> + { + ` + .markdown-body img{ + min-height: 200px; + } + ` + } + </style> + + + {this.state.isopentitletype==="greater"&&this.state.opentitletype===true? + <style> + { + ` + #shixunchallengesid{ + max-height:260px; + overflow: hidden; + } + ` + } + </style>:""} + {ChallengesDataList === undefined || ChallengesDataList&&ChallengesDataList.description=== ""||ChallengesDataList&&ChallengesDataList.description===null||ChallengesDataList&&ChallengesDataList.description===undefined?<style> + { + ` + #shixunchallengesid{ + max-height: 300px; + overflow: hidden; + } + ` + } + </style>:""} <div className="justify break_full_word new_li " id="challenge_editorMd_description"> diff --git a/public/react/src/modules/tpm/shixunchild/Challenges/Challengesjupyter.js b/public/react/src/modules/tpm/shixunchild/Challenges/Challengesjupyter.js index e04ad17c9..6ed139bc4 100644 --- a/public/react/src/modules/tpm/shixunchild/Challenges/Challengesjupyter.js +++ b/public/react/src/modules/tpm/shixunchild/Challenges/Challengesjupyter.js @@ -53,27 +53,47 @@ class Challengesjupyter extends Component { //console.log(error) }); } + + + getjianjiesize=()=>{ + let {ChallengesDataList}=this.state; + let boxoffsetHeigh; + let box=document.getElementById("shixunchallengesid"); + + if(box){ + boxoffsetHeigh=box.offsetHeight + if(ChallengesDataList === undefined || ChallengesDataList&&ChallengesDataList.description=== ""||ChallengesDataList&&ChallengesDataList.description===null||ChallengesDataList&&ChallengesDataList.description===undefined){ + + }else{ + if(this.state.isopentitletype==="greater"){ + + }else{ + if(boxoffsetHeigh>=300){ + this.setState({ + opentitletype:true, + isopentitletype:"greater", + boxoffsetHeigh:boxoffsetHeigh + }) + }else{ + this.setState({ + isopentitletype:"Less", + boxoffsetHeigh:boxoffsetHeigh + }) + } + } + + } + + } + } componentDidUpdate = (prevProps,prevState) => { //防止陷入无限循环 if(prevState.ChallengesDataList!=this.state.ChallengesDataList){ - let boxoffsetHeigh; - let box=document.getElementById("shixunchallengesid"); - if(box){ - boxoffsetHeigh=box.offsetHeight - if(boxoffsetHeigh<300){ - this.setState({ - isopentitletype:"Less", - boxoffsetHeigh:boxoffsetHeigh - }) - }else{ - this.setState({ - isopentitletype:"greater", - opentitletype:true, - boxoffsetHeigh:boxoffsetHeigh - }) - } + if(this.state.isopentitletype==="greater"){ + }else{ + this.getjianjiesize() } } @@ -122,6 +142,8 @@ class Challengesjupyter extends Component { }, 600) }); + + this.getjianjiesize() } updatamakedowns = () => { @@ -233,18 +255,30 @@ class Challengesjupyter extends Component { </a> </Tooltip> </div> - {this.state.opentitletype===true?<style> - { - ` + + <div> + + {this.state.isopentitletype==="greater"&&this.state.opentitletype===true? + <style> + { + ` + #shixunchallengesid{ + max-height:260px; + overflow: hidden; + } + ` + } + </style>:""} + {ChallengesDataList === undefined || ChallengesDataList&&ChallengesDataList.description=== ""||ChallengesDataList&&ChallengesDataList.description===null||ChallengesDataList&&ChallengesDataList.description===undefined?<style> + { + ` #shixunchallengesid{ max-height: 300px; overflow: hidden; } ` - } - </style>:""} - <div> - + } + </style>:""} <div className={"pd20"} id={"shixunchallengesid"}> <p id="ReactMarkdown" style={{overflow:'hidden'}}> {/*{ChallengesDataList === undefined ? "" :ChallengesDataList&&ChallengesDataList.description===null?"":*/} From 841a9fea0b0bf2e4118500934dc08cfce146dd5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=98=8E?= <775174143@qq.com> Date: Fri, 20 Dec 2019 11:31:22 +0800 Subject: [PATCH 38/39] =?UTF-8?q?=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tpm/shixunchild/Challenges/Challenges.js | 24 +++++++------ .../Challenges/Challengesjupyter.js | 35 ++++++++++++------- 2 files changed, 36 insertions(+), 23 deletions(-) diff --git a/public/react/src/modules/tpm/shixunchild/Challenges/Challenges.js b/public/react/src/modules/tpm/shixunchild/Challenges/Challenges.js index b1340c0de..239b46fd8 100644 --- a/public/react/src/modules/tpm/shixunchild/Challenges/Challenges.js +++ b/public/react/src/modules/tpm/shixunchild/Challenges/Challenges.js @@ -459,8 +459,19 @@ class Challenges extends Component { } </style> + {ChallengesDataList === undefined || ChallengesDataList&&ChallengesDataList.description=== ""||ChallengesDataList&&ChallengesDataList.description===null||ChallengesDataList&&ChallengesDataList.description===undefined?<style> + { + ` + #shixunchallengesid{ + max-height: 300px; + overflow: hidden; + } + ` + } + </style>:""} + - {this.state.isopentitletype==="greater"&&this.state.opentitletype===true? + {ChallengesDataList === undefined || ChallengesDataList&&ChallengesDataList.description=== ""||ChallengesDataList&&ChallengesDataList.description===null||ChallengesDataList&&ChallengesDataList.description===undefined?"":this.state.isopentitletype==="greater"&&this.state.opentitletype===true? <style> { ` @@ -471,16 +482,7 @@ class Challenges extends Component { ` } </style>:""} - {ChallengesDataList === undefined || ChallengesDataList&&ChallengesDataList.description=== ""||ChallengesDataList&&ChallengesDataList.description===null||ChallengesDataList&&ChallengesDataList.description===undefined?<style> - { - ` - #shixunchallengesid{ - max-height: 300px; - overflow: hidden; - } - ` - } - </style>:""} + <div className="justify break_full_word new_li " id="challenge_editorMd_description"> diff --git a/public/react/src/modules/tpm/shixunchild/Challenges/Challengesjupyter.js b/public/react/src/modules/tpm/shixunchild/Challenges/Challengesjupyter.js index 6ed139bc4..ca1e9d2ff 100644 --- a/public/react/src/modules/tpm/shixunchild/Challenges/Challengesjupyter.js +++ b/public/react/src/modules/tpm/shixunchild/Challenges/Challengesjupyter.js @@ -47,6 +47,7 @@ class Challengesjupyter extends Component { isopentitletype:"Less", }) } + this.getjianjiesize() } } }).catch((error) => { @@ -142,8 +143,8 @@ class Challengesjupyter extends Component { }, 600) }); + setTimeout(this.getjianjiesize(), 1000); - this.getjianjiesize() } updatamakedowns = () => { @@ -257,18 +258,16 @@ class Challengesjupyter extends Component { </div> <div> + <style> + { + ` + .markdown-body img{ + min-height: 200px; + } + ` + } + </style> - {this.state.isopentitletype==="greater"&&this.state.opentitletype===true? - <style> - { - ` - #shixunchallengesid{ - max-height:260px; - overflow: hidden; - } - ` - } - </style>:""} {ChallengesDataList === undefined || ChallengesDataList&&ChallengesDataList.description=== ""||ChallengesDataList&&ChallengesDataList.description===null||ChallengesDataList&&ChallengesDataList.description===undefined?<style> { ` @@ -279,6 +278,18 @@ class Challengesjupyter extends Component { ` } </style>:""} + {ChallengesDataList === undefined || ChallengesDataList&&ChallengesDataList.description=== ""||ChallengesDataList&&ChallengesDataList.description===null||ChallengesDataList&&ChallengesDataList.description===undefined?"":this.state.isopentitletype==="greater"&&this.state.opentitletype===true? + <style> + { + ` + #shixunchallengesid{ + max-height:260px; + overflow: hidden; + } + ` + } + </style>:""} + <div className={"pd20"} id={"shixunchallengesid"}> <p id="ReactMarkdown" style={{overflow:'hidden'}}> {/*{ChallengesDataList === undefined ? "" :ChallengesDataList&&ChallengesDataList.description===null?"":*/} From 981a5b97a68f996d49718eac485ce14718f14a2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=98=8E?= <775174143@qq.com> Date: Fri, 20 Dec 2019 11:40:07 +0800 Subject: [PATCH 39/39] =?UTF-8?q?=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/react/src/modules/tpm/TPMBanner.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/react/src/modules/tpm/TPMBanner.js b/public/react/src/modules/tpm/TPMBanner.js index da48a5b19..cde68f0b6 100644 --- a/public/react/src/modules/tpm/TPMBanner.js +++ b/public/react/src/modules/tpm/TPMBanner.js @@ -1016,8 +1016,8 @@ class TPMBanner extends Component { <Popover content={ <pre className={"bannerpd201"}> - <div>您编辑完成后,可以马上使用到自</div> - <div className={"wechatcenter mt10"}>己的课堂和实训课程哦</div> + <div>点击发布后,可以马上应用到自</div> + <div className={"wechatcenter mt10"}>己的课堂和课程</div> <div className={"wechatcenter mt15"}><Button type="primary" onClick={this.openknow} >我知道了</Button></div> </pre> }