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

dev_ec^2
cxt 5 years ago
commit 94a11a9200

@ -30,7 +30,7 @@ class Admins::SaveLaboratorySettingService < ApplicationService
hash = {}
hash[:name] = strip nav[:name]
hash[:link] = strip nav[:link]
hash[:hidden] = nav[:hidden].to_s == 0
hash[:hidden] = nav[:hidden].to_s != '0'
hash
end
end

@ -745,6 +745,7 @@ class Fileslists extends Component{
{/*选择资源*/}
{shixunmodal&&shixunmodal===true?<Selectresource
{...this.props}
{...this.state}
visible={this.state.shixunmodal}
shixunmodallist={this.state.shixunmodallist}
newshixunmodallist={this.state.newshixunmodallist}
@ -760,6 +761,7 @@ class Fileslists extends Component{
{/*上传资源*/}
{Accessoryvisible&&Accessoryvisible===true?<Sendresource
{...this.props}
{...this.state}
modalname={"上传资源"}
visible={Accessoryvisible}
Cancelname={"取消"}
@ -773,6 +775,7 @@ class Fileslists extends Component{
{/*设置资源*/}
{Settingtype&&Settingtype===true?<Selectsetting
{...this.props}
{...this.state}
Settingtype={Settingtype}
discussMessageid={discussMessageid}
course_id={this.props.match.params.coursesId}

@ -1,17 +1,34 @@
import React,{ Component } from "react";
import { Modal,Checkbox,Select,Input,Spin,Icon} from "antd";
import { Modal,Checkbox,Select,Input,Spin,Icon,Radio,DatePicker} from "antd";
import locale from 'antd/lib/date-picker/locale/zh_CN';
import axios from'axios';
import {handleDateString} from 'educoder';
import NoneData from "../coursesPublic/NoneData";
import Modals from '../../modals/Modals';
import moment from 'moment';
const Option = Select.Option;
const Search = Input.Search;
const dateFormat ="YYYY-MM-DD HH:mm"
function formatDate(date) {
var dateee = new Date(date).toJSON();
return new Date(+new Date(dateee) + 8 * 3600 * 1000).toISOString().replace(/T/g, ' ').replace(/\.[\d]{3}Z/, '')
}
function range(start, end) {
const result = [];
for (let i = start; i < end; i++) {
result.push(i);
}
return result;
}
function disabledDateTime() {
return {
disabledMinutes: () => range(1, 30).concat(range(31, 60)),
// disabledSeconds: () => range(1,60)
}
}
function disabledDate(current) {
return current && current < moment().endOf('day').subtract(1, 'days');
}
class Selectresource extends Component{
constructor(props){
super(props);
@ -23,7 +40,9 @@ class Selectresource extends Component{
Resourcelist:undefined,
hometypepvisible:true,
getallfiles:false,
searchtype:'getallfiles'
searchtype:'getallfiles',
Radiovalue:0,
datatime:undefined
}
}
componentDidMount() {
@ -32,11 +51,7 @@ class Selectresource extends Component{
componentDidUpdate = (prevProps) => {
let {getallfiles}=this.state;
if ( prevProps.visible != this.props.visible ) {
}
}
@ -197,7 +212,7 @@ class Selectresource extends Component{
savecouseShixunModal=()=>{
let {patheditarry}=this.state;
let {patheditarry,datatime,Radiovalue}=this.state;
let {coursesId,attachmentId}=this.props;
let url="/files/import.json";
@ -212,19 +227,28 @@ class Selectresource extends Component{
})
}
if(this.state.Radiovalue===1){
if(datatime===undefined||datatime===null||datatime=== ""){
this.setState({
Radiovaluetype:true
})
return
}else{
this.setState({
Radiovaluetype:false
})
}
}
axios.post(url, {
course_id:coursesId,
attachment_ids:patheditarry,
course_second_category_id:this.props.coursesidtype===undefined||this.props.coursesidtype==="node"?0:attachmentId,
delay_publish:Radiovalue,
publish_time:Radiovalue===1?datatime:undefined
}
).then((response) => {
if(response.data.status===0){
// this.setState({
// Modalstype:true,
// Modalstopval:response.data.message,
// ModalSave:this.ModalCancelModalCancel,
// loadtype:true
// })
this.ModalCancelModalCancel();
this.props.updataleftNavfun();
this.props.showNotification("选用资源成功");
@ -236,15 +260,33 @@ class Selectresource extends Component{
}
selectCloseList=(value)=>{
RadioonChange=(e)=>{
if(e.target.value===0){
this.setState({
datatime:undefined
})
}
this.setState({
Radiovalue: e.target.value,
});
}
onChangeTimepublish= (date, dateString) => {
this.setState({
category_id:value
datatime:handleDateString(dateString),
})
}
render(){
let {Searchvalue,type,category_id,Resourcelist,hometypepvisible,patheditarry}=this.state;
let {visible,shixunmodallist}=this.props;
let {Searchvalue,type,Resourcelist,hometypepvisible,patheditarry,datatime}=this.state;
let {visible}=this.props;
const antIcon = <Icon type="loading" style={{ fontSize: 24 }} spin />;
const radioStyle = {
display: 'block',
height: '30px',
lineHeight: '30px',
};
return(
<div>
{/*提示*/}
@ -373,10 +415,36 @@ class Selectresource extends Component{
}
</div>
<div className={"mt10"}>
<span className={"color-ooo fl mt6 ml20"}>发布设置</span>
<Radio.Group onChange={this.RadioonChange} value={this.state.Radiovalue} style={{'width': '460px'}}>
<Radio style={radioStyle} value={0}>
立即发布
</Radio>
<Radio style={radioStyle} value={1} className={"fl"}>
<span className={"mr5"}>延迟发布</span>
<DatePicker
dropdownClassName="hideDisable"
showTime={{ format: 'HH:mm' }}
locale={locale}
format={dateFormat}
placeholder="请选择发布时间"
id={"startime"}
showToday={false}
width={"210px"}
value={this.state.Radiovalue===1?datatime===undefined||datatime===""?undefined:moment(datatime, dateFormat):undefined}
onChange={(e,index)=>this.onChangeTimepublish(e,index,undefined,1)}
disabledTime={disabledDateTime}
disabledDate={disabledDate}
disabled={this.state.Radiovalue===1?false:true}
/>
</Radio>
<span className={"fl mt5 color-grey-c"}>(按照设置的时间定时发布)</span>
</Radio.Group>
</div>
{this.state.patheditarrytype===true?<p className={"color-red ml20"}>请选择资源</p>:""}
{this.state.Radiovaluetype===true?<p className={"color-red ml20"}>发布时间不能为空</p>:""}
<div className="mt20 marginauto clearfix edu-txt-center">
<a className="pop_close task-btn mr30 margin-tp26" onClick={this.hidecouseShixunModal}>取消</a>
<a className="task-btn task-btn-orange margin-tp26" id="submit_send_shixun" onClick={this.savecouseShixunModal}>确定</a>

@ -38,7 +38,8 @@ class Selectsetting extends Component{
datatime:undefined,
fileList:[],
fileListtype:false,
is_public:false
is_public:false,
Radiovaluetype:false
}
}
@ -79,9 +80,8 @@ class Selectsetting extends Component{
description: response.data.description,
is_public:response.data.is_public,
datatime:response.data.publish_time,
// is_public:response.data.course_groups,
Radiovalue:response.data.delay_publish===false?0:1,
//attachment_histories:response.data.attachment_histories
course_groups:newcourse_groups
})
}
@ -91,23 +91,6 @@ class Selectsetting extends Component{
});
let coursesId=this.props.match.params.coursesId;
if(this.props.isAdmin()){
let url = `/courses/${coursesId}/all_course_groups.json`
axios.get(url, {
})
.then((response) => {
this.setState({
course_groupss: response.data.course_groups,
})
})
.catch(function (error) {
console.log(error);
});
}
}
@ -146,13 +129,26 @@ class Selectsetting extends Component{
}
savecouseShixunModal=()=>{
let {fileList,is_public,description,datatime,course_groups}=this.state;
let {fileList,is_public,description,datatime,Radiovalue}=this.state;
let newfileList=[];
for(var list of fileList){
newfileList.push(list.response.id)
}
if(this.state.Radiovalue===1){
if(datatime===undefined||datatime===null||datatime=== ""){
this.setState({
Radiovaluetype:true
})
return
}else{
this.setState({
Radiovaluetype:false
})
}
}
if(description===undefined||description===null){
}else if(description.length>100){
@ -171,11 +167,10 @@ class Selectsetting extends Component{
new_attachment_id:newfileList.length===0?undefined:newfileList,
course_second_category_id:this.props.coursesidtype===undefined||this.props.coursesidtype==="node"?0:attachmentId,
is_public:is_public,
publish_time:unified_setting===true?datatime===undefined?moment(new Date()).format('YYYY-MM-DD HH'):datatime:undefined,
publish_time:Radiovalue===0?undefined:datatime===undefined?moment(new Date(),dateFormat):datatime,
description:description,
course_group_publish_times:unified_setting===false?course_groups:undefined
delay_publish:Radiovalue
}).then((result)=>{
if(result.data.status===0){
this.props.setupdate(attachmentId)
this.props.showNotification("设置资源成功");
@ -241,10 +236,23 @@ class Selectsetting extends Component{
fileList:[]
})
}
}
onChangepublic=(e)=>{
this.setState({
is_public:e.target.checked
})
}
RadioonChange=(e)=>{
if(e.target.value===0){
this.setState({
datatime:undefined
})
}
this.setState({
Radiovalue: e.target.value,
});
}
render(){
let {datatime,description,datalist}=this.state;
@ -267,6 +275,8 @@ class Selectsetting extends Component{
height: '30px',
lineHeight: '30px',
};
console.log(this.state.datatime)
return(
<div>
<style>
@ -479,16 +489,6 @@ class Selectsetting extends Component{
margin-top:10px;
}
`}</style>
{this.props.course_is_public===true?<div>
<span className={"color-ooo"}>公开</span><Checkbox checked={this.state.is_public} onChange={this.onChangepublic}>
<span className={"font-14 color-ooo"}>选中所有用户可见否则课堂成员可见</span>
</Checkbox>
</div>:""}
<style>
{`
.Selectleft20{
@ -502,7 +502,11 @@ class Selectsetting extends Component{
}
`}
</style>
{this.props.course_is_public===true?<div>
<span className={"color-ooo"}>公开</span><Checkbox checked={this.state.is_public} onChange={(e)=>this.onChangepublic(e)}>
<span className={"font-14 color-ooo"}>选中所有用户可见否则课堂成员可见</span>
</Checkbox>
</div>:""}
</p>
<style>
{`
@ -514,13 +518,14 @@ class Selectsetting extends Component{
<div className={this.props.course_is_public===true?"mt10":""}>
<span className={"color-ooo fl mt6"}>发布设置</span>
<Radio.Group onChange={this.RadioonChange} value={this.state.Radiovalue} style={{'width': '460px'}}>
<Radio.Group onChange={(e)=>this.RadioonChange(e)} value={this.state.Radiovalue} style={{'width': '460px'}}>
<Radio style={radioStyle} value={0}>
立即发布
</Radio>
<Radio style={radioStyle} value={1} className={"fl"}>
<span className={"mr5"}>延迟发布</span>
<DatePicker
showToday={false}
dropdownClassName="hideDisable"
showTime={{ format: 'HH:mm' }}
@ -548,6 +553,7 @@ class Selectsetting extends Component{
padding: '10px'
}}></textarea>
{this.state.descriptiontypes===true?<p className={"color-red"}>描述不能超过最大限制100个字符</p>:""}
{this.state.Radiovaluetype===true?<p className={"color-red"}>发布时间不能为空</p>:""}
</div>
<div className="mt20 marginauto clearfix edu-txt-center">

@ -1,9 +1,11 @@
import React, { Component } from "react";
import { Modal, Checkbox, Input, Spin} from "antd";
import axios from 'axios'
import axios from 'axios';
import moment from 'moment';
import ModalWrapper from "../common/ModalWrapper";
import InfiniteScroll from 'react-infinite-scroller';
const dateFormat ="YYYY-MM-DD HH:mm"
const Search = Input.Search
const pageCount = 15;
class Sendtofilesmodal extends Component{
@ -170,7 +172,12 @@ class Sendtofilesmodal extends Component{
bottom: 93px;
width: 82%;
text-align: center;
}`}
}
.ModalWrappertitle{
background: #D0E8FC;
padding: 10px;
}
`}
</style>
<p className="color-grey-6 mb20 edu-txt-center" style={{ fontWeight: "bold" }} >选择的{moduleName}发送到<span className="color-orange-tip">指定课堂</span></p>
@ -183,7 +190,12 @@ class Sendtofilesmodal extends Component{
></Search>
<div>
{/* https://github.com/CassetteRocks/react-infinite-scroller/issues/70 */}
<p className="clearfix ModalWrappertitle">
<div className="task-hide fl pagemancenter" style={{"width":'215px'}}>课堂名称</div>
<div className="task-hide fl pagemancenter" style={{"width":'140px'}}>更新时间</div>
<div className="task-hide fl pagemancenter" style={{"width":'110px'}}>结束时间</div>
</p>
<div className="edu-back-skyblue padding15" style={{"height":"300px", overflowY: "scroll", overflowAnchor: 'none' }}>
<InfiniteScroll
threshold={10}
@ -199,20 +211,14 @@ class Sendtofilesmodal extends Component{
return (
<p className="clearfix mb7" key={course.id}>
<Checkbox className="fl" value={course.id} key={course.id} ></Checkbox>
<span className="fl with45"><label className="task-hide fl" style={{"maxWidth":"208px;"}}>{course.name}</label></span>
<div className="task-hide fl" style={{"width":'215px'}} title={course.name}>{course.name}</div>
<div className="task-hide fl" style={{"width":'140px'}}>{moment(course.updated_at).format('YYYY-MM-DD HH:mm')}</div>
<div className="task-hide fl" style={{"width":'110px'}}>{course.end_date}</div>
</p>
)
}) }
</Checkbox.Group>
{loading && hasMore && (
<div className="demo-loading-container">
<Spin />
</div>
)}
{/* TODO */}
{/* {
!hasMore && <div>没有更多了</div>
} */}
</InfiniteScroll>
</div>

@ -58,23 +58,6 @@ class Sendresource extends Component{
componentDidMount() {
let coursesId=this.props.match.params.coursesId;
if(this.props.isAdmin()){
let url = `/courses/${coursesId}/all_course_groups.json`
axios.get(url, {
})
.then((response) => {
this.setState({
course_groups: response.data.course_groups,
course_groups_count:response.data.course_groups_count
})
})
.catch(function (error) {
console.log(error);
});
}
}
//勾选实训
@ -245,6 +228,11 @@ class Sendresource extends Component{
}
RadioonChange=(e)=>{
if(e.target.value===0){
this.setState({
datatime:undefined
})
}
this.setState({
Radiovalue: e.target.value,
});
@ -411,6 +399,7 @@ class Sendresource extends Component{
<Radio style={radioStyle} value={1} className={"fl"}>
<span className={"mr5"}>延迟发布</span>
<DatePicker
dropdownClassName="hideDisable"
showTime={{ format: 'HH:mm' }}
locale={locale}

@ -1,4 +1,4 @@
import React, { useState, useEffect } from 'react'
import React, { useState, useEffect, memo } from 'react'
import { trigger, WordsBtn } from 'educoder'
import { Input, Checkbox, Popconfirm } from "antd";
import axios from 'axios'
@ -8,9 +8,11 @@ import axios from 'axios'
*/
function ChangeRolePop({ member_roles = [], record, courseId, onChangeRoleSuccess, showNotification, getUserId, fetchUser }) {
const [checkBoxRoles, setCheckBoxRoles] = useState(member_roles)
useEffect(() => {
setCheckBoxRoles(member_roles)
}, [member_roles])
// useEffect(() => {
// if (checkBoxRoles.length != member_roles.length) { // 死循环
// setCheckBoxRoles(member_roles)
// }
// }, [member_roles])
function onCheckBoxChange(val) {
console.log(val)
@ -77,4 +79,4 @@ function ChangeRolePop({ member_roles = [], record, courseId, onChangeRoleSucces
</Popconfirm>
)
}
export default ChangeRolePop
export default memo(ChangeRolePop)

@ -152,7 +152,7 @@ function CourseGroupList(props) {
</React.Fragment> }
{
// pageType !== TYPE_STUDENTS &&
!isCourseEnd && isAdmin && isParent && <WordsBtn style="blue" className="mr30" onClick={()=>addDir()}>新建分班</WordsBtn> }
!isCourseEnd && isAdmin && <WordsBtn style="blue" className="mr30" onClick={()=>addDir()}>新建分班</WordsBtn> }
{/* {
isAdmin && !isParent && course_group_id != 0 && <WordsBtn style="blue" className="mr30" onClick={()=>deleteDir()}>删除分班</WordsBtn> } */}
{/* {

@ -28,7 +28,6 @@ function CourseGroupListTable(props) {
}
course_groups.forEach((record) => {
const id = record.id
debugger;
let _clipboard = new ClipboardJS(`.copyBtn_${id}`);
_clipboard.on('success', (e) => {
props.showNotification('复制成功')
@ -142,7 +141,7 @@ function CourseGroupListTable(props) {
return columns
}
const addToDir = async (record) => {
const doAddToDir = async (record) => {
const courseId = props.match.params.coursesId
const url = `/courses/${courseId}/join_course_group.json`
const course_group_id = record.id
@ -151,11 +150,27 @@ function CourseGroupListTable(props) {
course_group_id
})
if (response && response.data.status == 0) {
props.showNotification('加入成功')
props.showNotification(`已加入分班:${record.name}`)
props.updataleftNavfun()
props.onOperationSuccess && props.onOperationSuccess()
}
}
const addToDir = (record) => {
props.confirm({
content: `是否确认加入分班: ${record.name}?`,
okText: '确认',
cancelText: '取消',
onOk: () => {
doAddToDir(record)
},
onCancel() {
console.log('Cancel');
},
});
}
function onDelete(record) {
props.confirm({

@ -130,7 +130,7 @@ const buildColumns = (that,isParent) => {
}
const isAdmin = that.props.isAdmin()
if (isAdmin) {
columns.unshift({
!that.isStudentPage && columns.unshift({
title: '',
dataIndex: 'check',
key: 'check',
@ -149,7 +149,7 @@ const buildColumns = (that,isParent) => {
return (
<React.Fragment>
<WordsBtn style2={{ marginRight: '12px' }} onClick={() => that.onDelete(record)} style={'grey'}>删除学生</WordsBtn>
<ChangeRolePop
{record.member_roles && record.member_roles.length && <ChangeRolePop
courseId={courseId}
record={record}
member_roles={record.member_roles}
@ -157,7 +157,7 @@ const buildColumns = (that,isParent) => {
showNotification={that.props.showNotification}
getUserId={that.props.isUserid}
fetchUser={that.props.fetchUser}
></ChangeRolePop>
></ChangeRolePop>}
</React.Fragment>
)
},
@ -547,7 +547,7 @@ class studentsList extends Component{
addDir = () => {
trigger('groupAdd', this.props.coursesids)
}
addToDir = async () => {
doAddToDir = async () => {
const courseId = this.props.match.params.coursesId
const url = `/courses/${courseId}/join_course_group.json`
const course_group_id = this.props.match.params.course_group_id
@ -556,11 +556,27 @@ class studentsList extends Component{
course_group_id
})
if (response && response.data.status == 0) {
this.props.showNotification('加入成功')
this.props.showNotification(`已加入分班:${this.state.course_group_name}`)
this.props.updataleftNavfun()
this.fetchAll()
}
}
addToDir = (record) => {
this.props.confirm({
content: `是否确认加入分班: ${this.state.course_group_name}?`,
okText: '确认',
cancelText: '取消',
onOk: () => {
this.doAddToDir()
},
onCancel() {
console.log('Cancel');
},
});
}
renameDir = () => {
const course_group_id = this.props.match.params.course_group_id
trigger('groupRename', { id: parseInt(course_group_id), name: this.state.course_group_name})
@ -670,7 +686,8 @@ class studentsList extends Component{
} else {
pageType = TYPE_COURSE_GOURP_CHILD
}
const isStudentPage = pageType == TYPE_STUDENTS
this.isStudentPage = isStudentPage
return(
<React.Fragment >
@ -708,23 +725,24 @@ class studentsList extends Component{
searchPlaceholder={ '请输入姓名、学号进行搜索' }
firstRowRight={
<React.Fragment>
{
{/* {
// pageType !== TYPE_STUDENTS &&
isSuperAdmin && <React.Fragment>
!isStudentPage && isSuperAdmin && <React.Fragment>
<CreateGroupByImportModal ref="createGroupByImportModal" {...this.props}
createGroupImportSuccess={this.createGroupImportSuccess}
></CreateGroupByImportModal>
<WordsBtn style="blue" className="mr30" onClick={()=> this.refs['createGroupByImportModal'].setVisible(true)}>导入创建分班</WordsBtn>
</React.Fragment> }
</React.Fragment> } */}
{
// pageType !== TYPE_STUDENTS &&
!isCourseEnd && isAdmin && isParent && <WordsBtn style="blue" className="mr30" onClick={()=>this.addDir()}>添加分班</WordsBtn> }
!isStudentPage && isAdmin && !isParent && course_group_id != 0 && <WordsBtn style="blue" className="mr30" onClick={()=>this.deleteDir()}>删除分班</WordsBtn> }
{
isStudent && !isParent && course_group_id != 0 && <WordsBtn style="blue" className="mr30" onClick={()=>this.addToDir()}>加入分班</WordsBtn> }
!isStudentPage && isAdmin && !isParent && course_group_id != 0 && <WordsBtn style="blue" className="mr30" onClick={()=>this.renameDir()}>分班重命名</WordsBtn> }
{
isAdmin && !isParent && course_group_id != 0 && <WordsBtn style="blue" className="mr30" onClick={()=>this.deleteDir()}>删除分班</WordsBtn> }
!isStudentPage && !isCourseEnd && isAdmin && <WordsBtn style="blue" className="mr30" onClick={()=>this.addDir()}>新建分班</WordsBtn> }
{
isAdmin && !isParent && course_group_id != 0 && <WordsBtn style="blue" className="mr30" onClick={()=>this.renameDir()}>分班重命名</WordsBtn> }
!isStudentPage && isStudent && !isParent && course_group_id != 0 && <WordsBtn style="blue" className="mr30" onClick={()=>this.addToDir()}>加入分班</WordsBtn> }
<style>{`
.drop_down_menu li a {
padding: 0px;
@ -780,10 +798,10 @@ class studentsList extends Component{
total_count > 0 || this.state.isSpin == true ?
<div className="mt20 edu-back-white padding20">
<div className="clearfix stu_head" style={{paddingLeft: '15px'}}>
{isAdmin && <Checkbox className="fl" onChange={this.onCheckAll} checked={checkAllValue} >已选 {checkBoxValues.length} </Checkbox>}
{isAdmin && !isStudentPage && <Checkbox className="fl" onChange={this.onCheckAll} checked={checkAllValue} >已选 {checkBoxValues.length} </Checkbox>}
<div className="studentList_operation_ul">
{/* {isAdmin && <li className="li_line"><a href="javascript:void(0)" className="color-grey-9" onClick={this.onDelete}>删除</a></li>} */}
{isAdmin && <li className="drop_down">
{isAdmin && !isStudentPage && <li className="drop_down">
移动到...<i className="iconfont icon-xiajiantou font-12 ml2"></i>
<ul className="drop_down_menu" style={{"right":"0px","left":"unset", width: '200px', maxHeight: '324px', overflowY: 'auto'}}>
{

Loading…
Cancel
Save