Merge branch 'dev_aliyun' of https://bdgit.educoder.net/Hjqreturn/educoder into dev_aliyun

courseware
daiao 5 years ago
commit 65f1f7ca73

@ -81,19 +81,20 @@ class AttendancesController < ApplicationController
old_group_ids = @attendance.course_attendance_groups.pluck(:course_group_id)
unless old_group_ids.include?(0)
all_groups_ids = old_group_ids + params[:group_ids].map(&:to_i)
# 如果新增的的分班加上之前的分班是课堂的全部分班,则只需创建一条记录
if all_groups_ids.uniq.count == @course.course_groups_count
@attendance.course_attendance_groups.destroy_all
@attendance.course_attendance_groups.create!(course_group_id: 0, course_id: @attendance.course_id)
new_group = true
else
new_group_ids = params[:group_ids] - old_group_ids
# all_groups_ids = old_group_ids + params[:group_ids].map(&:to_i)
# 如果新增的的分班加上之前的分班是课堂的全部分班,则只需创建一条记录(未分班需要区分考虑,不需要这步)
# if all_groups_ids.uniq.count == @course.course_groups_count
# @attendance.course_attendance_groups.destroy_all
# @attendance.course_attendance_groups.create!(course_group_id: 0, course_id: @attendance.course_id)
# new_group = true
# else
new_group = false
new_group_ids = params[:group_ids].map(&:to_i) - old_group_ids
new_group_ids.each do |group_id|
@attendance.course_attendance_groups.create!(course_group_id: group_id, course_id: @attendance.course_id)
new_group = true
end
end
# end
end

@ -816,7 +816,7 @@ class ExercisesController < ApplicationController
ex_user_ids = exercise_users.pluck(:id)
EndExerciseCalculateJob.perform_later(ex_user_ids, exercise, Time.now.to_s, true, 4)
EndExerciseCalculateJob.perform_later(ex_user_ids, exercise.id, Time.now.to_s, true, 4)
# exercise_users.each do |user|
# if user.commit_status == 0 && user.start_at.present?
# objective_score = calculate_student_score(exercise,user.user)[:total_score]
@ -1194,7 +1194,7 @@ class ExercisesController < ApplicationController
start_time = Time.current - @exercise.time * 60
ex_user_ids = @exercise_users_list.where("start_at <= '#{Time.at(start_time)}' and commit_status = 0").pluck(:id)
if ex_user_ids.size > 0
EndExerciseCalculateJob.perform_later(ex_user_ids, @exercise, Time.now.to_s, false, 2)
EndExerciseCalculateJob.perform_later(ex_user_ids, @exercise.id, Time.now.to_s, false, 2)
end
end

@ -11,15 +11,15 @@ class Weapps::AttendancesController < ApplicationController
attendance = @course.course_attendances.create!(create_params.merge(user_id: current_user.id))
group_ids = params[:group_ids] || []
group_ids = group_ids.blank? ? @course.charge_group_ids(current_user) : @course.charge_group_ids(current_user) & params[:group_ids].map(&:to_i)
unless group_ids.blank? || @course.course_groups.where(id: group_ids).count == @course.course_groups.count
if group_ids.blank? || (params[:group_ids].blank? && @course.course_groups.where(id: group_ids).count == @course.course_groups.count)
@course.course_attendance_groups.create!(course_group_id: 0, course_attendance: attendance)
CreateStudentAttendanceRecordJob.perform_now(attendance.id, [0])
else
# group_ids = @course.charge_group_ids(current_user) & params[:group_ids].map(&:to_i)
group_ids.each do |group_id|
@course.course_attendance_groups.create!(course_group_id: group_id, course_attendance: attendance)
end
CreateStudentAttendanceRecordJob.perform_now(attendance.id, group_ids)
else
@course.course_attendance_groups.create!(course_group_id: 0, course_attendance: attendance)
CreateStudentAttendanceRecordJob.perform_now(attendance.id, [0])
end
render_ok({attendance_id: attendance.id})
end

@ -7,7 +7,7 @@ class CourseVideoUploadedJob < ApplicationJob
return unless course_ids.present?
course_members = CourseMember.where(course_id: course_ids, role: 'STUDENT').select("user_id, course_id")
course_members = CourseMember.where(course_id: course_ids, role: 'STUDENT').select("id, user_id, course_id")
Tiding.bulk_insert do |worker|
course_members.find_each do |m|
worker.add(

@ -5,7 +5,9 @@ class EndExerciseCalculateJob < ApplicationJob
queue_as :default
def perform(ex_user_ids,exercise,end_time,work_time,commit_method)
def perform(ex_user_ids,exercise_id,end_time,work_time,commit_method)
exercise = Exercise.find_by(id: exercise_id)
return if exercise.blank?
exercise_users = ExerciseUser.where(id: ex_user_ids)
exercise_users.each do |user|
if user.commit_status == 0 && user.start_at.present?

@ -11,7 +11,7 @@ module UserOnline
def set_bit(user_id, flag)
if !Rails.cache.data.exists(cache_key)
Rails.cache.data.setbit(cache_key, user_id, flag)
Rails.cache.data.expire(cache_key, 20 * 60 + 10)
Rails.cache.data.expire(cache_key, 2 * 60 + 10)
else
Rails.cache.data.setbit(cache_key, user_id, flag)
end
@ -27,11 +27,11 @@ module UserOnline
def cache_key
if Rails.cache.is_a?(ActiveSupport::Cache::RedisStore)
# 10分钟为一段记录用户在线, 统计范围为20分钟内的线用户
# 如设置2分钟内即120秒有请求的用户视为在线, 则最大会统计到4分钟内有活动用户
# TODO 更精确时长
begin_hour = Time.now.beginning_of_hour
minutes_piece = (Time.now - begin_hour) / 600
time = begin_hour.since((minutes_piece.to_i - 1) * 600).strftime("%H-%M")
minutes_piece = (Time.now - begin_hour) / 120
time = begin_hour.since((minutes_piece.to_i - 1) * 120).strftime("%H-%M")
"online_user_#{time}"
else
raise '请配置config.cache_store = redis_store'

@ -769,7 +769,7 @@ function showcity(province, cityField) {
var cityOptions = new Array("福州","厦门","泉州","漳州","龙岩","南平","宁德","莆田","三明");
break;
case "甘肃":
var cityOptions = new Array("兰州","白银","定西","敦煌","甘南","金昌","酒泉","临夏","平凉","天水","武都","武威","西峰","张掖");
var cityOptions = new Array("兰州","白银","定西","敦煌","甘南","金昌","酒泉","临夏","平凉","天水","陇南","武威","西峰","张掖");
break;
case "广西":
var cityOptions = new Array("南宁","百色","北海","桂林","防城港","贵港","河池","贺州","柳州","钦州","梧州","玉林");
@ -1267,7 +1267,7 @@ function opClickString(item) {
operationItem = item
// setTimeout(function(){ $(item).css('background', '#4CACFF');$(item).html(value); }, 4000)
}
//
//
// var isOperationSending = false;
$(document).bind('ajaxStop', function(event, xhr, settings) {
if (settings && settings.url && (settings.url.match(/operation\?/))) {

@ -91,6 +91,7 @@
"react-router-dom": "^4.2.2",
"react-split-pane": "^0.1.89",
"react-url-query": "^1.4.0",
"react-zmage": "^0.8.5-beta.31",
"redux": "^4.0.0",
"redux-thunk": "2.3.0",
"rsuite": "^4.0.1",

@ -46,7 +46,7 @@ debugType = "admin";
// 老师
// debugType="teacher";
// 学生
debugType="student";
// debugType="student";

@ -524,8 +524,8 @@ const options = [{
value: '天水',
label: '天水'
},{
value: '武都',
label: '武都'
value: '陇南',
label: '陇南'
},{
value: '武威',
label: '武威'

@ -18,8 +18,8 @@ function ImageLayer2(props) {
const fileName = event.target.innerHTML.trim()
if (isImageExtension((imageSrc && imageSrc.trim())) || isImageExtension(fileName) || event.target.tagName == 'IMG' || (imageSrc && imageSrc.indexOf('base64,')) != -1) {
// 非回复里的头像图片; 非emoticons
if (imageSrc.indexOf('/images/avatars/User') === -1 &&
imageSrc.indexOf('kindeditor/plugins/emoticons') === -1 ) {
if (imageSrc.indexOf('/images/avatars/User') === -1 &&
imageSrc.indexOf('kindeditor/plugins/emoticons') === -1 ) {
setShowImage(true)
setImageSrc(imageSrc)
}
@ -41,7 +41,7 @@ function ImageLayer2(props) {
})
return (
<ImageLayer showImage={showImage} imageSrc={imageSrc} onImageLayerClose={onImageLayerClose}></ImageLayer>
showImage?<ImageLayer showImage={showImage} imageSrc={imageSrc} onImageLayerClose={onImageLayerClose}></ImageLayer>:""
)
}

@ -137,6 +137,9 @@ class TPIContextProvider extends Component {
this.costTimeInterval && window.clearInterval(this.costTimeInterval)
}
componentDidMount() {
window.$(window).unload( ()=>{
console.log(12321)
});
// TODO 登录状态的判断?
// request
@ -158,12 +161,24 @@ class TPIContextProvider extends Component {
}
}, 1000)
// 页面离开时存下用户的任务耗时
// 页面离开时存下用户的任务耗时
window.$(window).bind('beforeunload', function (e) {
console.log(111111)
this._updateCostTime();
})
// // 页面离开时存下用户的任务耗时
// window.$(window).unload( ()=>{
// this._updateCostTime();
// });
window.$(window).unload( ()=>{
this._updateCostTime();
});
}
// force 评测通过后异步执行该方法强制同步costTime到服务端
_updateCostTime(async = false, force) {
const { game, loading } = this.state;

@ -107,6 +107,15 @@ class CommonWorkAppraise extends Component{
}
gotoget_next_work=(id)=>{
if(this.props.match.path===`/classrooms/:coursesId/common_homework/:workId/:studentWorkId/appraise`){
this.props.history.replace(`/classrooms/${this.props.match.params.coursesId}/common_homeworks/${this.props.match.params.workId}/${id}/appraise`);
}
if(this.props.match.path===`/classrooms/:coursesId/group_homework/:workId/:studentWorkId/appraise`){
this.props.history.replace(`/classrooms/${this.props.match.params.coursesId}/common_homeworks/${this.props.match.params.workId}/${id}/appraise`);
}
if(this.props.match.path===`/classrooms/:coursesId/common_homeworks/:workId/:studentWorkId/appraise`){
this.props.history.replace(`/classrooms/${this.props.match.params.coursesId}/common_homeworks/${this.props.match.params.workId}/${id}/appraise`);
}
@ -114,6 +123,7 @@ class CommonWorkAppraise extends Component{
if(this.props.match.path===`/classrooms/:coursesId/group_homeworks/:workId/:studentWorkId/appraise`){
this.props.history.replace(`/classrooms/${this.props.match.params.coursesId}/common_homeworks/${this.props.match.params.workId}/${id}/appraise`);
}
this.setState({
get_next_worktype:false
})

@ -617,11 +617,13 @@ class CoursesBanner extends Component {
</p>
</div>
<div className="fl mt13">
<p className="color-white bannnerusernames">{coursedata.teacher_school}</p>
</div>
</div>
{/*{excellent===false?*/}
{/* :*/}

@ -94,12 +94,12 @@ class CoursesHomeCard extends Component{
</Tooltip>
</p>
<div style={{height:30,overflow: 'hidden',textOverflow:'ellipsis',whiteSpace: 'nowrap'}}>
<div className="task-hide" style={{height:25,marginBottom:10}}>
{item.teacher_users.length===0?'':
<span className="color-grey-98" style={{height:30,display:'flex'}}>协作老师
<span className="color-grey-98" >协作老师
{item.teacher_users.map((iem,idx)=>{
return(
<span v-if={idx<3} style={{marginLeft:5}}>{iem} </span>
<span className="task-hide" style={{width:50,marginLeft:5}}>{idx<3?iem:''} </span>
)
})
}

@ -547,8 +547,9 @@ class Trainingjobsetting extends Component {
}
} else {
//不是统一设置
//分班设置
// console.log("分班设置");
console.log("分班设置");
// console.log(this.$pollDetailTabForthRules);
const result=this.$pollDetailTabForthRules.notUnifiedSettingCheck(this.state.rules);
@ -561,11 +562,79 @@ class Trainingjobsetting extends Component {
return false;
}
let rulesdata = this.state.rulesdata;
if (rulesdata.length === 0) {
this.props.showNotification(`分班发布设置不能为空`);
return;
}
}
}else{
// console.log("分班设置");
var mylate_times=false;
if (this.state.unifiedsetting === false) {
///非统一设置
let rulesdata = this.state.rulesdata;
//开启了补交
if(this.state.allowreplenishment===true){
//补交结束时间不为空
if(this.state.late_time){
// 分班设置数组不为空
if(rulesdata){
for(var i=0;i<rulesdata.length-1;i++){
let item=rulesdata[i];
if(item.end_time!=="Invalid date"){
let emdtimes=null;
try {
emdtimes= moment(item.end_time, "YYYY-MM-DD HH:mm")
}catch (e) {
}
if(emdtimes){
if(moment(this.state.late_time, "YYYY-MM-DD HH:mm") <= emdtimes){
mylate_times=true;
let kus=i+1;
this.setState({
hand__e_tip: "补交时间必须晚于发布规则" +kus+ "的截止时间",
hand_flags: true,
handclass: "bor-reds",
});
this.props.showNotification(`补交结束时间必须晚于截止时间`);
break;
}else{
mylate_times=false;
this.setState({
hand__e_tip: "",
hand_flags: false,
handclass: undefined,
})
}
}
}
}
}
}
}
if(mylate_times){
this.scrollToAnchor("late_timeids");
return
}
}else{
///统一设置
}
}
@ -787,22 +856,27 @@ class Trainingjobsetting extends Component {
// console.log(JSON.stringify(data));
axios.post(url, data)
.then((result) => {
if (result.data.status == 0) {
// console.log(JSON.stringify(result));
this.getTrainingjobsetting(true);
this.props.showNotification(`更新成功`);
this.setState({
flagPageEditsbox: false,
flagPageEdit: false,
flagPageEditstwo: false,
flagPageEditsthrees: false,
flagPageEditsfor: false,
whethertopay: false,
completionefficiencyscore: false,
})
this.refs.targetElementTrainingjobsetting.scrollIntoView()
if(result){
if(result.data){
if (result.data.status == 0) {
// console.log(JSON.stringify(result));
this.getTrainingjobsetting(true);
this.props.showNotification(`更新成功`);
this.setState({
flagPageEditsbox: false,
flagPageEdit: false,
flagPageEditstwo: false,
flagPageEditsthrees: false,
flagPageEditsfor: false,
whethertopay: false,
completionefficiencyscore: false,
})
this.refs.targetElementTrainingjobsetting.scrollIntoView()
}
}
}
}).catch((error) => {
console.log(error);
})
@ -2577,7 +2651,7 @@ class Trainingjobsetting extends Component {
</div>
{/*补交设置*/}
<div className="stud-class-set bor-bottom-greyE edu-back-white">
<div className="stud-class-set bor-bottom-greyE edu-back-white" id={"late_timeids"}>
<div className=" clearfix edu-back-white poll_list mt10">
<div className={"font-16 color-dark fl pl20 mt10 "} style={{color: "#05101A"}}>补交设置</div>
</div>
@ -2660,7 +2734,7 @@ class Trainingjobsetting extends Component {
<p className="color-red lineh-25 clearfix ml70" style={{height: "25px"}}>
{
this.state.hand__e_tip && this.state.hand__e_tip != "" ?
<span className="fl">{this.state.hand__e_tip}</span> : ""
<span className="fl ml10">{this.state.hand__e_tip}</span> : ""
}
</p>
</div>
@ -2929,75 +3003,3 @@ class Trainingjobsetting extends Component {
}
export default Trainingjobsetting;
// <div className="stud-class-set bor-bottom-greyE ">
// <div className=" clearfix edu-back-white poll_list">
// <a onClick={(e)=>this.ChangeTab(0)}>作品列表</a>
// <a onClick={(e)=>this.ChangeTab(1)}>作业问答</a>
// {this.props.isAdmin()?this.state.code_review===true||jobsettingsdata === undefined ? [""] : jobsettingsdata.data.homework_status[0]==="未发布"?"": <a onClick={(e)=>this.ChangeTab(2)}>代码查重</a> : ""}
// <style>{
// `
// .poll_list a.active:after {
// content: '';
// width: 57px;
// left: 10px;
// bottom: 0px;
// height: 2px;
// background-color: #4CACFF;
// position: absolute;
// }
// `
// }</style>
// <a className="active"
// onClick={(e)=>this.ChangeTab(3)}
// >设置</a>
// <style>{`
// .drop_down_menu li a {
// padding: 0px;
// font-size: 14px;
// }
// .drop_down_menu {
// width: 93px;
// }
// .drop_down_menu li {
// overflow: visible;
// width: 93px;
// }
// .drop_down_menu, .drop_down_normal {
// padding-top: 10px;
// padding-bottom: 8px;
// }
// a:hover {
// color:#1A0B00 !important;
// }
// `}</style>
// {this.props.isAdmin() ? <li className="li_line drop_down fr color-blue font-16 mr8 mt20" style={{"padding": "0 20px"}}>
// 导出<i className="iconfont icon-xiajiantou font-12 ml2"></i>
// <ul className="drop_down_menu" style={{"right": "-0px", "left": "unset", "height": "auto"}}>
// <li><a onClick={()=>this.confirmysl(`/zip/shixun_report?homework_common_id=${this.props.match.params.homeworkid}`)}>实训报告</a>
// </li>
// <li><a onClick={()=>this.confirmysl(`/homework_commons/${this.props.match.params.homeworkid}/works_list.xlsx`)}>学生成绩</a>
// </li>
// </ul>
// </li>: ""}
// {this.props.isAdmin() ?jobsettingsdata&&jobsettingsdata.data.end_immediately===true?
// <a className="fr color-blue font-16" onClick={this.homeworkends}>立即截止</a>
// : "": ""}
// {this.props.isAdmin() ?jobsettingsdata&&jobsettingsdata.data.publish_immediately===true?
// <a className="fr color-blue font-16" onClick={this.homeworkstart}>立即发布</a>: "" : ""}
// {this.props.isAdmin()?
// jobsettingsdata&&jobsettingsdata.data.code_review===true?
// <a className="fr color-blue font-16" onClick={this.workshowmodel}>代码查重</a>: "":""}
// {
// jobsettingsdata&& jobsettingsdata&&jobsettingsdata.data === undefined ? ""
// : jobsettingsdata&& jobsettingsdata.data.commit_des === null || jobsettingsdata&& jobsettingsdata.data.commit_des === undefined ? "" :
// <a className="fr color-blue font-16"
// href={`/courses/${this.state.props.match.params.coursesId}/${this.state.shixuntypes}/${ jobsettingsdata&& jobsettingsdata.data === undefined ? "" : jobsettingsdata&& jobsettingsdata.data.id}/commitsummary/${this.state.props.match.params.homeworkid}`}>{ jobsettingsdata&& jobsettingsdata.data.commit_des}</a>
// }
// { jobsettingsdata&&jobsettingsdata.data === undefined ? "" : <Startshixuntask
// {...this.props}
// data={ jobsettingsdata&& jobsettingsdata.data}
// />}
{/* </div>*/
}
{/*</div>*/
}

@ -59,7 +59,7 @@ class LeftNav extends Component {
<div className="leftnav" style={{position: 'fixed', bottom:0}}>
<a href="/shixuns/uznmbg54?exit=true" className="leftnav-box-inner" id="exit_task_tab">
<i className="fa fa-arrow-left font-20"></i><br/><span className="font-12">退出实训</span>
<i className="fa fa-arrow-left font-20"></i><br/><span className="font-12">退出实训1</span>
</a>
</div>

@ -1,26 +1,63 @@
import React, { Component } from 'react';
import ReactDOM from 'react-dom'
import { Redirect } from 'react-router';
import PropTypes from 'prop-types';
import Rate from 'rc-rate';
import { Button,Icon} from 'antd';
import './TaskResultLayer.css'
class ImageLayer extends Component {
constructor(props) {
super(props);
this.state = {
visible: false,
previewImage: '',
current: 90,
transStyle: ''
}
}
translate = () => {
this.setState({
current:(this.state.current+90)%360,
transStyle:'rotate('+this.state.current+'deg)'
});
}
render() {
let { showImage, imageSrc, onImageLayerClose } = this.props;
// 语法介绍 https://reactjs.org/docs/portals.html
// 将html渲染都指定的element下
return ReactDOM.createPortal(
<div>
{showImage ?
<div className="taskResultLayer" onClick={onImageLayerClose} style={{overflow: 'auto'}}>
<div className="passContent">
<img src={ imageSrc } className="passImg" unselectable="on" alt=""/>
</div>
{showImage ?
<div className="taskResultLayer">
<div className={"ImageLayerbutton mt20"}>
<Button
className={"fr"}
onClick={()=>this.props.onImageLayerClose()}
>
关闭<Icon type="close" />
</Button>
<Button
href={imageSrc}
className={"fr mr10"}
>
下载<Icon type="vertical-align-bottom" />
</Button>
<Button
onClick = {()=>this.translate()}
className={"fr mr10"}
>
旋转<Icon type="reload" theme="outlined" />
</Button>
</div>
<div className="passContent" style={{ transform:this.state.transStyle}}>
<img src={imageSrc} className="passImg" unselectable="on" alt=""/>
</div>
</div>
:
<div></div>

@ -7,7 +7,7 @@
background:rgba(0,0,0,0.8);
top: 0px;
overflow: hidden;
}
}
.taskResultLayer .closeIcon{
position: absolute;
right: 100px;
@ -40,7 +40,7 @@
justify-content: center;
align-items: center;
display: -webkit-flex;
height: 100%;
height: 90%;
text-align: center;
}
.passImg{
@ -137,4 +137,11 @@
.vertical4{
vertical-align: -4px;
}
.ImageLayerbutton{
position: absolute;
top: 0px;
right: 10px;
z-index: 10;
}

@ -346,9 +346,9 @@ class InfosCourse extends Component{
<span><img alt="用户" className="radius mt15" height="50" src={getImageUrl('images/'+`${item.teacher && item.teacher.avatar_url}`)} width="50"/></span>
<p className="font-14 mt10 task-hide"><span>{item.teacher && item.teacher.real_name}</span></p>
<p className="font-16 mb15 task-hide mt10"><span className="color-grey-98">{item&&item.school}</span></p>
<div style={{height:20,overflow: 'hidden',textOverflow:'ellipsis',whiteSpace: 'nowrap',marginBottom:5}}>
<div className="task-hide" style={{height:30 }}>
{item.teacher_users.length===0?'':
<span className="color-grey-98" style={{height:30,display:'flex'}}>协作老师
<span className="color-grey-98">协作老师
{item.teacher_users.map((iem,idx)=>{
return(
<span v-if={idx<3} style={{marginLeft:5}}>{iem} </span>

@ -289,7 +289,7 @@ class InfosPath extends Component{
lineHeight: "41px",
marginTop: "10px",
}}>
<span className="fl color-grey-9">{category && category == "collect" ?"共收藏":"共参与"}{totalCount}{category?category=="manage"?"发布":"学习":"实践课程"}</span>
<span className="fl color-grey-9">{category && category == "collect" ?"共收藏":"共参与"}{totalCount}{category && category == "collect"?"":category?category=="manage"?"发布":"学习":"实践课程"}</span>
<sapn className="relativef color-grey-9 fr"
style={{
display: "flex",

@ -309,7 +309,7 @@ class InfosShixun extends Component{
lineHeight: "41px",
marginTop: "10px",
}}>
<span className="fl color-grey-9">{category && category == "collect"?"共收藏":"共参与"}{totalCount}{category?category=="manage"?"发布":"学习":"实训"}</span>
<span className="fl color-grey-9">{category && category == "collect"?"共收藏":"共参与"}{totalCount}{category && category == "collect"?"":category?category=="manage"?"发布":"学习":"实训"}</span>
<sapn className="relativef color-grey-9 fr"
style={{
display: "flex",

Loading…
Cancel
Save