Merge branch 'master' of https://bdgit.educoder.net/Hjqreturn/educoder
commit
68ea96e61b
File diff suppressed because it is too large
Load Diff
@ -1,153 +1,153 @@
|
||||
import React,{Component} from "React";
|
||||
import { Form, Select, Input, Button,Checkbox,Icon,message,Modal, Table, Divider, Tag,DatePicker,Radio,Tooltip} from "antd";
|
||||
import {Link} from 'react-router-dom';
|
||||
import { WordsBtn, MarkdownToHtml } from 'educoder';
|
||||
import axios from 'axios';
|
||||
import PublishRightnow from '../PublishRightnow'
|
||||
import AccessoryModal from "../../coursesPublic/AccessoryModal";
|
||||
|
||||
const { Option} = Select;
|
||||
const CheckboxGroup = Checkbox.Group;
|
||||
const confirm = Modal.confirm;
|
||||
let GraduationTasksnewtype=true;
|
||||
const $ = window.$;
|
||||
const Search = Input.Search;
|
||||
const RadioGroup = Radio.Group;
|
||||
|
||||
class TabRightComponents extends Component{
|
||||
|
||||
constructor(props){
|
||||
super(props)
|
||||
|
||||
this.publishModal = React.createRef();
|
||||
this.endModal = React.createRef();
|
||||
|
||||
this.state={
|
||||
accessoryVisible: false
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
}
|
||||
|
||||
onToPublishClick = () => {
|
||||
|
||||
}
|
||||
// 补交附件
|
||||
Cancelvisible=()=>{
|
||||
this.setState({
|
||||
accessoryVisible:false
|
||||
})
|
||||
}
|
||||
|
||||
addAccessory=()=>{
|
||||
this.setState({
|
||||
accessoryVisible:true
|
||||
})
|
||||
}
|
||||
setupdate = () => {
|
||||
|
||||
}
|
||||
render(){
|
||||
const dateFormat = 'YYYY-MM-DD HH:mm';
|
||||
const { accessoryVisible } = this.state
|
||||
let { work_statuses, publish_immediately, work_id
|
||||
, end_immediately
|
||||
} =this.props;
|
||||
|
||||
let courseId=this.props.match.params.coursesId;
|
||||
let category_id=this.props.match.params.category_id;
|
||||
let workId=this.props.match.params.workId;
|
||||
|
||||
const isGroup = this.props.isGroup()
|
||||
const moduleName = !isGroup? "普通作业":"分组作业";
|
||||
const moduleEngName = this.props.getModuleName()
|
||||
|
||||
const childModuleName = this.props.moduleName
|
||||
|
||||
const isAdmin = this.props.isAdmin()
|
||||
const isSuperAdmin = this.props.isSuperAdmin()
|
||||
|
||||
let exportUrl = `/api/homework_commons/${workId}/works_list.zip`
|
||||
const exportResultUrl = `/api/homework_commons/${workId}/works_list.xlsx`
|
||||
|
||||
return(
|
||||
<React.Fragment>
|
||||
{isAdmin ?
|
||||
<React.Fragment>
|
||||
<div style={{display: 'inline', float: 'right'}}>
|
||||
<PublishRightnow ref={this.publishModal} showActionButton={false} {...this.props} checkBoxValues={[workId]}
|
||||
isPublish={true} doWhenSuccess={this.props.doWhenSuccess} checkBeforePost={this.props.saveWorkSetting}
|
||||
onToPublishClick={this.onToPublishClick}
|
||||
></PublishRightnow>
|
||||
<PublishRightnow ref={this.endModal} showActionButton={false} {...this.props} checkBoxValues={[workId]}
|
||||
isPublish={false} doWhenSuccess={this.props.doWhenSuccess}></PublishRightnow>
|
||||
</div>
|
||||
|
||||
<style>{`
|
||||
.drop_down_menu li a {
|
||||
padding: 0px;
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
}
|
||||
.drop_down_menu {
|
||||
width: 121px;
|
||||
}
|
||||
.drop_down_menu li {
|
||||
overflow: visible;
|
||||
width: 121px;
|
||||
}
|
||||
.drop_down_menu, .drop_down_normal {
|
||||
padding-top: 10px;
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
`}</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":"-34px","left":"unset","height":"auto"}}>
|
||||
<li><a href={exportResultUrl} calssName="color-dark">导出成绩</a></li>
|
||||
<li><a href={exportUrl} calssName="color-dark">导出作品附件</a></li>
|
||||
</ul>
|
||||
</li>:""}
|
||||
|
||||
{/* <a className={"fr color-blue font-16"} href={exportUrl}>导出作品附件</a>
|
||||
<a className={"fr color-blue font-16"} href={exportResultUrl}>导出成绩</a> */}
|
||||
{/*<a className={"fr color-blue font-16"}>导出</a>*/}
|
||||
{end_immediately && <a className={"fr color-blue font-16"} onClick={() => { this.endModal.current.open() } }>立即截止</a>}
|
||||
{publish_immediately && <a className={"fr color-blue font-16"} onClick={() => { this.publishModal.current.open() } } >立即发布</a>}
|
||||
|
||||
{/*<a className={"fr color-blue font-16"}>项目在线质量检测</a>*/}
|
||||
{isAdmin && <a className={"fr color-blue font-16"} onClick={() => this.props.toEditPage(this.props.match.params, workId)}>编辑作业</a>}
|
||||
</React.Fragment> :
|
||||
<React.Fragment>
|
||||
{work_statuses && work_statuses.indexOf('提交作品') != -1 && <a className={"fr color-blue font-16"} href={"javascript:void(0)"}
|
||||
onClick={() => { this.props.toWorkPostPage(this.props.match.params)}}
|
||||
>提交作品</a>}
|
||||
{work_statuses && work_statuses.indexOf('修改作品') != -1 && <a className={"fr color-blue font-16"} href={"javascript:void(0)"}
|
||||
onClick={() => { this.props.toWorkPostPage(this.props.match.params, null, true, work_id)}}
|
||||
>修改作品</a>}
|
||||
{work_statuses && work_statuses.indexOf('补交附件') != -1 &&
|
||||
<React.Fragment>
|
||||
<AccessoryModal
|
||||
{...this.props}
|
||||
modalname={"补交附件"}
|
||||
visible={accessoryVisible}
|
||||
Cancelname={"取消"}
|
||||
Savesname={"确认"}
|
||||
Cancel={this.Cancelvisible}
|
||||
setupdate={this.setupdate}
|
||||
reviseAttachmentUrl={`/student_works/${work_id}/revise_attachment.json`}
|
||||
/>
|
||||
<a className={"fr color-blue font-16"} href={"javascript:void(0)"}
|
||||
onClick={this.addAccessory}
|
||||
>补交附件</a>
|
||||
</React.Fragment>
|
||||
}
|
||||
</React.Fragment> }
|
||||
</React.Fragment>
|
||||
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import React,{Component} from "React";
|
||||
import { Form, Select, Input, Button,Checkbox,Icon,message,Modal, Table, Divider, Tag,DatePicker,Radio,Tooltip} from "antd";
|
||||
import {Link} from 'react-router-dom';
|
||||
import { WordsBtn, MarkdownToHtml } from 'educoder';
|
||||
import axios from 'axios';
|
||||
import PublishRightnow from '../PublishRightnow'
|
||||
import AccessoryModal from "../../coursesPublic/AccessoryModal";
|
||||
|
||||
const { Option} = Select;
|
||||
const CheckboxGroup = Checkbox.Group;
|
||||
const confirm = Modal.confirm;
|
||||
let GraduationTasksnewtype=true;
|
||||
const $ = window.$;
|
||||
const Search = Input.Search;
|
||||
const RadioGroup = Radio.Group;
|
||||
|
||||
class TabRightComponents extends Component{
|
||||
|
||||
constructor(props){
|
||||
super(props)
|
||||
|
||||
this.publishModal = React.createRef();
|
||||
this.endModal = React.createRef();
|
||||
|
||||
this.state={
|
||||
accessoryVisible: false
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
}
|
||||
|
||||
onToPublishClick = () => {
|
||||
|
||||
}
|
||||
// 补交附件
|
||||
Cancelvisible=()=>{
|
||||
this.setState({
|
||||
accessoryVisible:false
|
||||
})
|
||||
}
|
||||
|
||||
addAccessory=()=>{
|
||||
this.setState({
|
||||
accessoryVisible:true
|
||||
})
|
||||
}
|
||||
setupdate = () => {
|
||||
|
||||
}
|
||||
render(){
|
||||
const dateFormat = 'YYYY-MM-DD HH:mm';
|
||||
const { accessoryVisible } = this.state
|
||||
let { work_statuses, publish_immediately, work_id
|
||||
, end_immediately
|
||||
} =this.props;
|
||||
|
||||
let courseId=this.props.match.params.coursesId;
|
||||
let category_id=this.props.match.params.category_id;
|
||||
let workId=this.props.match.params.workId;
|
||||
|
||||
const isGroup = this.props.isGroup()
|
||||
const moduleName = !isGroup? "普通作业":"分组作业";
|
||||
const moduleEngName = this.props.getModuleName()
|
||||
|
||||
const childModuleName = this.props.moduleName
|
||||
|
||||
const isAdmin = this.props.isAdmin()
|
||||
const isSuperAdmin = this.props.isSuperAdmin()
|
||||
|
||||
let exportUrl = `/api/homework_commons/${workId}/works_list.zip`
|
||||
const exportResultUrl = `/api/homework_commons/${workId}/works_list.xlsx`
|
||||
|
||||
return(
|
||||
<React.Fragment>
|
||||
{isAdmin ?
|
||||
<React.Fragment>
|
||||
<div style={{display: 'inline', float: 'right'}}>
|
||||
<PublishRightnow ref={this.publishModal} showActionButton={false} {...this.props} checkBoxValues={[workId]}
|
||||
isPublish={true} doWhenSuccess={this.props.doWhenSuccess} checkBeforePost={this.props.saveWorkSetting}
|
||||
onToPublishClick={this.onToPublishClick}
|
||||
></PublishRightnow>
|
||||
<PublishRightnow ref={this.endModal} showActionButton={false} {...this.props} checkBoxValues={[workId]}
|
||||
isPublish={false} doWhenSuccess={this.props.doWhenSuccess}></PublishRightnow>
|
||||
</div>
|
||||
|
||||
<style>{`
|
||||
.drop_down_menu li a {
|
||||
padding: 0px;
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
}
|
||||
.drop_down_menu {
|
||||
width: 121px;
|
||||
}
|
||||
.drop_down_menu li {
|
||||
overflow: visible;
|
||||
width: 121px;
|
||||
}
|
||||
.drop_down_menu, .drop_down_normal {
|
||||
padding-top: 10px;
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
`}</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":"-34px","left":"unset","height":"auto"}}>
|
||||
<li><a href={exportResultUrl} className="color-dark">导出成绩</a></li>
|
||||
<li><a href={exportUrl} className="color-dark">导出作品附件</a></li>
|
||||
</ul>
|
||||
</li>:""}
|
||||
|
||||
{/* <a className={"fr color-blue font-16"} href={exportUrl}>导出作品附件</a>
|
||||
<a className={"fr color-blue font-16"} href={exportResultUrl}>导出成绩</a> */}
|
||||
{/*<a className={"fr color-blue font-16"}>导出</a>*/}
|
||||
{end_immediately && <a className={"fr color-blue font-16"} onClick={() => { this.endModal.current.open() } }>立即截止</a>}
|
||||
{publish_immediately && <a className={"fr color-blue font-16"} onClick={() => { this.publishModal.current.open() } } >立即发布</a>}
|
||||
|
||||
{/*<a className={"fr color-blue font-16"}>项目在线质量检测</a>*/}
|
||||
{isAdmin && <a className={"fr color-blue font-16"} onClick={() => this.props.toEditPage(this.props.match.params, workId)}>编辑作业</a>}
|
||||
</React.Fragment> :
|
||||
<React.Fragment>
|
||||
{work_statuses && work_statuses.indexOf('提交作品') != -1 && <a className={"fr color-blue font-16"} href={"javascript:void(0)"}
|
||||
onClick={() => { this.props.toWorkPostPage(this.props.match.params)}}
|
||||
>提交作品</a>}
|
||||
{work_statuses && work_statuses.indexOf('修改作品') != -1 && <a className={"fr color-blue font-16"} href={"javascript:void(0)"}
|
||||
onClick={() => { this.props.toWorkPostPage(this.props.match.params, null, true, work_id)}}
|
||||
>修改作品</a>}
|
||||
{work_statuses && work_statuses.indexOf('补交附件') != -1 &&
|
||||
<React.Fragment>
|
||||
<AccessoryModal
|
||||
{...this.props}
|
||||
modalname={"补交附件"}
|
||||
visible={accessoryVisible}
|
||||
Cancelname={"取消"}
|
||||
Savesname={"确认"}
|
||||
Cancel={this.Cancelvisible}
|
||||
setupdate={this.setupdate}
|
||||
reviseAttachmentUrl={`/student_works/${work_id}/revise_attachment.json`}
|
||||
/>
|
||||
<a className={"fr color-blue font-16"} href={"javascript:void(0)"}
|
||||
onClick={this.addAccessory}
|
||||
>补交附件</a>
|
||||
</React.Fragment>
|
||||
}
|
||||
</React.Fragment> }
|
||||
</React.Fragment>
|
||||
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default TabRightComponents;
|
@ -1,235 +1,235 @@
|
||||
import React, { Component } from "react";
|
||||
import { Modal, Checkbox, Input, Spin, Select, Divider } from "antd";
|
||||
import axios from 'axios'
|
||||
import ModalWrapper from "../../common/ModalWrapper"
|
||||
import InfiniteScroll from 'react-infinite-scroller';
|
||||
import { ConditionToolTip } from 'educoder'
|
||||
const Option = Select.Option;
|
||||
const pageCount = 15;
|
||||
|
||||
// 代码查重弹框
|
||||
class CheckCodeModal extends Component{
|
||||
constructor(props){
|
||||
super(props);
|
||||
this.state={
|
||||
checkBoxValues: [],
|
||||
candidates: [],
|
||||
hasMore: true,
|
||||
loading: false,
|
||||
page: 1
|
||||
}
|
||||
}
|
||||
fetchMemberList = (arg_page) => {
|
||||
const courseId = this.props.match.params.coursesId
|
||||
const page = arg_page || this.state.page;
|
||||
const { name, school_name } = this.state
|
||||
let url = `/courses/${courseId}/search_teacher_candidate.json`
|
||||
this.setState({ loading: true })
|
||||
axios.post(url, {
|
||||
page: page,
|
||||
limit: pageCount,
|
||||
school_name: school_name || '',
|
||||
name: name || ''
|
||||
})
|
||||
.then((response) => {
|
||||
if (!response.data.candidates || response.data.candidates.length == 0) {
|
||||
this.setState({
|
||||
page,
|
||||
loading: false,
|
||||
hasMore: false,
|
||||
})
|
||||
} else {
|
||||
this.setState({
|
||||
candidates: page == 1 ? response.data.candidates : this.state.candidates.concat(response.data.candidates),
|
||||
page,
|
||||
loading: false,
|
||||
hasMore: response.data.candidates.length == pageCount
|
||||
})
|
||||
}
|
||||
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
componentDidMount() {
|
||||
|
||||
|
||||
}
|
||||
fetchOptions = () => {
|
||||
// add_teacher_popup
|
||||
const courseId = this.props.match.params.coursesId
|
||||
|
||||
let url = `/courses/${courseId}/add_teacher_popup.json`
|
||||
|
||||
axios.get(url, {
|
||||
})
|
||||
.then((response) => {
|
||||
if (response.data.graduation_groups) {
|
||||
this.setState({
|
||||
graduation_groups: response.data.graduation_groups
|
||||
})
|
||||
}
|
||||
if (response.data.course_groups) {
|
||||
this.setState({
|
||||
course_groups: response.data.course_groups
|
||||
})
|
||||
}
|
||||
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
setVisible = (visible) => {
|
||||
if (visible) {
|
||||
this.fetchMemberList()
|
||||
this.fetchOptions()
|
||||
}
|
||||
this.refs.modalWrapper.setVisible(visible)
|
||||
if (visible == false) {
|
||||
this.setState({
|
||||
checkBoxValues: []
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
onSendOk = () => {
|
||||
const courseId = this.props.match.params.coursesId
|
||||
const url = `/courses/${courseId}/add_teacher.json`
|
||||
const params = {
|
||||
"user_list": this.state.checkBoxValues.map (item => { return { 'user_id': item }}) ,
|
||||
"graduation_group_id": "2",
|
||||
"course_group_id": "820",
|
||||
// "role": ROLE_TEACHER_NUM
|
||||
}
|
||||
const { graduationGroup, courseGroup } = this.state
|
||||
if (graduationGroup) {
|
||||
params.graduation_group_id = graduationGroup
|
||||
}
|
||||
if (courseGroup) {
|
||||
params.course_group_id = courseGroup
|
||||
}
|
||||
axios.post(url, params)
|
||||
.then((response) => {
|
||||
if (response.data.status == 0) {
|
||||
this.setVisible(false)
|
||||
this.props.showNotification('添加成功')
|
||||
}
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
|
||||
onOk = () => {
|
||||
this.onSendOk()
|
||||
}
|
||||
|
||||
onCheckBoxChange = (checkBoxValues) => {
|
||||
this.setState({
|
||||
checkBoxValues: checkBoxValues
|
||||
})
|
||||
}
|
||||
|
||||
handleInfiniteOnLoad = () => {
|
||||
this.fetchMemberList(this.state.page + 1)
|
||||
}
|
||||
|
||||
onSearch = () => {
|
||||
this.fetchMemberList(1)
|
||||
}
|
||||
handleGradationGroupChange = (value) => {
|
||||
this.setState({
|
||||
graduationGroup: value
|
||||
})
|
||||
}
|
||||
handleCourseGroupChange = (value) => {
|
||||
this.setState({
|
||||
courseGroup: value
|
||||
})
|
||||
}
|
||||
render(){
|
||||
const { candidates, checkBoxValues, loading, hasMore, name, school_name
|
||||
, graduationGroup, graduation_groups, courseGroup, course_groups } = this.state
|
||||
const { moduleName } = this.props
|
||||
return(
|
||||
<ModalWrapper
|
||||
ref="modalWrapper"
|
||||
width="700px"
|
||||
title={`代码查重`}
|
||||
{...this.props }
|
||||
onOk={this.onOk}
|
||||
className="checkCodeModal"
|
||||
>
|
||||
<style>
|
||||
{`
|
||||
.demo-loading-container {
|
||||
position: absolute;
|
||||
bottom: 93px;
|
||||
width: 82%;
|
||||
text-align: center;
|
||||
}
|
||||
.df {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
margin: 12px 0;
|
||||
}
|
||||
.firstLabel {
|
||||
flex: 0 0 60px;
|
||||
}
|
||||
.df span.label {
|
||||
margin-right: 8px;
|
||||
text-align: right;
|
||||
margin-left: 12px;
|
||||
}
|
||||
.df .ant-input-affix-wrapper {
|
||||
width: 32%;
|
||||
}
|
||||
|
||||
.checkCodeModal label.task-hide {
|
||||
width: 100%;
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
|
||||
<p className="clearfix mb2" style={{ margin: '0px 15px 6px' }}>
|
||||
<Checkbox className="fl" style={{ visibility: 'hidden' }} ></Checkbox>
|
||||
<span className="fl with25"><label className="task-hide fl" style={{"maxWidth":"208px;"}}>{'分班名称'}</label></span>
|
||||
<span className="fl with25"><label className="task-hide fl" style={{"maxWidth":"208px;"}}>{'有效作品数'}</label></span>
|
||||
<span className="fl with45"><label className="task-hide fl" style={{"maxWidth":"208px;"}}>{'上次查重时间'}</label></span>
|
||||
|
||||
</p>
|
||||
<div>
|
||||
{/* https://github.com/CassetteRocks/react-infinite-scroller/issues/70 */}
|
||||
<div className="edu-back-skyblue padding10-15" style={{"height":"300px", overflowY: "scroll", overflowAnchor: 'none' }}>
|
||||
<Checkbox.Group style={{ width: '100%' }} onChange={this.onCheckBoxChange} value={checkBoxValues}>
|
||||
|
||||
{ candidates && candidates.map( candidate => {
|
||||
return (
|
||||
<p className="clearfix mb7" key={candidate.id}>
|
||||
<Checkbox className="fl" value={candidate.id} ></Checkbox>
|
||||
<span className="fl with25">
|
||||
<ConditionToolTip title={candidate.name} condition={candidate.name && candidate.name.length > 12 }>
|
||||
<label className="task-hide fl" style={{"maxWidth":"208px;"}}>{candidate.name}</label>
|
||||
</ConditionToolTip>
|
||||
</span>
|
||||
<span className="fl with25">
|
||||
<ConditionToolTip title={candidate.nickname} condition={candidate.nickname && candidate.nickname.length > 12 }>
|
||||
<label className="task-hide fl" style={{"maxWidth":"208px;"}}>{candidate.nickname}</label>
|
||||
</ConditionToolTip>
|
||||
</span>
|
||||
<span className="fl with45"><label className="task-hide fl" style={{"maxWidth":"208px;"}}>{candidate.school_name}</label></span>
|
||||
|
||||
</p>
|
||||
)
|
||||
}) }
|
||||
</Checkbox.Group>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</ModalWrapper>
|
||||
)
|
||||
}
|
||||
}
|
||||
export default CheckCodeModal;
|
||||
import React, { Component } from "react";
|
||||
import { Modal, Checkbox, Input, Spin, Select, Divider } from "antd";
|
||||
import axios from 'axios'
|
||||
import ModalWrapper from "../../common/ModalWrapper"
|
||||
import InfiniteScroll from 'react-infinite-scroller';
|
||||
import { ConditionToolTip } from 'educoder'
|
||||
const Option = Select.Option;
|
||||
const pageCount = 15;
|
||||
|
||||
// 代码查重弹框
|
||||
class CheckCodeModal extends Component{
|
||||
constructor(props){
|
||||
super(props);
|
||||
this.state={
|
||||
checkBoxValues: [],
|
||||
candidates: [],
|
||||
hasMore: true,
|
||||
loading: false,
|
||||
page: 1
|
||||
}
|
||||
}
|
||||
fetchMemberList = (arg_page) => {
|
||||
const courseId = this.props.match.params.coursesId
|
||||
const page = arg_page || this.state.page;
|
||||
const { name, school_name } = this.state
|
||||
let url = `/courses/${courseId}/search_teacher_candidate.json`
|
||||
this.setState({ loading: true })
|
||||
axios.post(url, {
|
||||
page: page,
|
||||
limit: pageCount,
|
||||
school_name: school_name || '',
|
||||
name: name || ''
|
||||
})
|
||||
.then((response) => {
|
||||
if (!response.data.candidates || response.data.candidates.length == 0) {
|
||||
this.setState({
|
||||
page,
|
||||
loading: false,
|
||||
hasMore: false,
|
||||
})
|
||||
} else {
|
||||
this.setState({
|
||||
candidates: page == 1 ? response.data.candidates : this.state.candidates.concat(response.data.candidates),
|
||||
page,
|
||||
loading: false,
|
||||
hasMore: response.data.candidates.length == pageCount
|
||||
})
|
||||
}
|
||||
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
componentDidMount() {
|
||||
|
||||
|
||||
}
|
||||
fetchOptions = () => {
|
||||
// add_teacher_popup
|
||||
const courseId = this.props.match.params.coursesId
|
||||
|
||||
let url = `/courses/${courseId}/add_teacher_popup.json`
|
||||
|
||||
axios.get(url, {
|
||||
})
|
||||
.then((response) => {
|
||||
if (response.data.graduation_groups) {
|
||||
this.setState({
|
||||
graduation_groups: response.data.graduation_groups
|
||||
})
|
||||
}
|
||||
if (response.data.course_groups) {
|
||||
this.setState({
|
||||
course_groups: response.data.course_groups
|
||||
})
|
||||
}
|
||||
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
setVisible = (visible) => {
|
||||
if (visible) {
|
||||
this.fetchMemberList()
|
||||
this.fetchOptions()
|
||||
}
|
||||
this.refs.modalWrapper.setVisible(visible)
|
||||
if (visible == false) {
|
||||
this.setState({
|
||||
checkBoxValues: []
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
onSendOk = () => {
|
||||
const courseId = this.props.match.params.coursesId
|
||||
const url = `/courses/${courseId}/add_teacher.json`
|
||||
const params = {
|
||||
"user_list": this.state.checkBoxValues.map (item => { return { 'user_id': item }}) ,
|
||||
"graduation_group_id": "2",
|
||||
"course_group_id": "820",
|
||||
// "role": ROLE_TEACHER_NUM
|
||||
}
|
||||
const { graduationGroup, courseGroup } = this.state
|
||||
if (graduationGroup) {
|
||||
params.graduation_group_id = graduationGroup
|
||||
}
|
||||
if (courseGroup) {
|
||||
params.course_group_id = courseGroup
|
||||
}
|
||||
axios.post(url, params)
|
||||
.then((response) => {
|
||||
if (response.data.status == 0) {
|
||||
this.setVisible(false)
|
||||
this.props.showNotification('添加成功')
|
||||
}
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
|
||||
onOk = () => {
|
||||
this.onSendOk()
|
||||
}
|
||||
|
||||
onCheckBoxChange = (checkBoxValues) => {
|
||||
this.setState({
|
||||
checkBoxValues: checkBoxValues
|
||||
})
|
||||
}
|
||||
|
||||
handleInfiniteOnLoad = () => {
|
||||
this.fetchMemberList(this.state.page + 1)
|
||||
}
|
||||
|
||||
onSearch = () => {
|
||||
this.fetchMemberList(1)
|
||||
}
|
||||
handleGradationGroupChange = (value) => {
|
||||
this.setState({
|
||||
graduationGroup: value
|
||||
})
|
||||
}
|
||||
handleCourseGroupChange = (value) => {
|
||||
this.setState({
|
||||
courseGroup: value
|
||||
})
|
||||
}
|
||||
render(){
|
||||
const { candidates, checkBoxValues, loading, hasMore, name, school_name
|
||||
, graduationGroup, graduation_groups, courseGroup, course_groups } = this.state
|
||||
const { moduleName } = this.props
|
||||
return(
|
||||
<ModalWrapper
|
||||
ref="modalWrapper"
|
||||
width="700px"
|
||||
title={`代码查重`}
|
||||
{...this.props }
|
||||
onOk={this.onOk}
|
||||
className="checkCodeModal"
|
||||
>
|
||||
<style>
|
||||
{`
|
||||
.demo-loading-container {
|
||||
position: absolute;
|
||||
bottom: 93px;
|
||||
width: 82%;
|
||||
text-align: center;
|
||||
}
|
||||
.df {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
margin: 12px 0;
|
||||
}
|
||||
.firstLabel {
|
||||
flex: 0 0 60px;
|
||||
}
|
||||
.df span.label {
|
||||
margin-right: 8px;
|
||||
text-align: right;
|
||||
margin-left: 12px;
|
||||
}
|
||||
.df .ant-input-affix-wrapper {
|
||||
width: 32%;
|
||||
}
|
||||
|
||||
.checkCodeModal label.task-hide {
|
||||
width: 100%;
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
|
||||
<p className="clearfix mb2" style={{ margin: '0px 15px 6px' }}>
|
||||
<Checkbox className="fl" style={{ visibility: 'hidden' }} ></Checkbox>
|
||||
<span className="fl with25"><label className="task-hide fl" style={{"maxWidth":"208px;"}}>{'分班名称'}</label></span>
|
||||
<span className="fl with25"><label className="task-hide fl" style={{"maxWidth":"208px;"}}>{'有效作品数'}</label></span>
|
||||
<span className="fl with45"><label className="task-hide fl" style={{"maxWidth":"208px;"}}>{'上次查重时间'}</label></span>
|
||||
|
||||
</p>
|
||||
<div>
|
||||
{/* https://github.com/CassetteRocks/react-infinite-scroller/issues/70 */}
|
||||
<div className="edu-back-skyblue padding10-15" style={{"height":"300px", overflowY: "scroll", overflowAnchor: 'none' }}>
|
||||
<Checkbox.Group style={{ width: '100%' }} onChange={this.onCheckBoxChange} value={checkBoxValues}>
|
||||
|
||||
{ candidates && candidates.map( candidate => {
|
||||
return (
|
||||
<p className="clearfix mb7" key={candidate.id}>
|
||||
<Checkbox className="fl" value={candidate.id} ></Checkbox>
|
||||
<span className="fl with25">
|
||||
<ConditionToolTip title={candidate.name} condition={candidate.name && candidate.name.length > 12 }>
|
||||
<label className="task-hide fl" style={{"maxWidth":"208px;"}}>{candidate.name}</label>
|
||||
</ConditionToolTip>
|
||||
</span>
|
||||
<span className="fl with25">
|
||||
<ConditionToolTip title={candidate.nickname} condition={candidate.nickname && candidate.nickname.length > 12 }>
|
||||
<label className="task-hide fl" style={{"maxWidth":"208px;"}}>{candidate.nickname}</label>
|
||||
</ConditionToolTip>
|
||||
</span>
|
||||
<span className="fl with45"><label className="task-hide fl" style={{"maxWidth":"208px;"}}>{candidate.school_name}</label></span>
|
||||
|
||||
</p>
|
||||
)
|
||||
}) }
|
||||
</Checkbox.Group>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</ModalWrapper>
|
||||
)
|
||||
}
|
||||
}
|
||||
export default CheckCodeModal;
|
||||
|
@ -1,181 +1,186 @@
|
||||
import React, {Component} from "react";
|
||||
import {WordsBtn} from 'educoder';
|
||||
import {Table} from "antd";
|
||||
import {Link,Switch,Route,Redirect} from 'react-router-dom';
|
||||
|
||||
class OfficialAcademicTranscript extends Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
loadingstate:true,
|
||||
datas:undefined
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
let {data}=this.props;
|
||||
let datas=[];
|
||||
// data&&data.exercise_counts.forEach((item,key)=>{ })
|
||||
|
||||
datas.push({
|
||||
commit_percent:data&&data.exercise_counts.commit_percent,
|
||||
min_score:data&&data.exercise_counts.min_score,
|
||||
max_score:data&&data.exercise_counts.max_score,
|
||||
average_score:data&&data.exercise_counts.average_score,
|
||||
fail_counts:data&&data.exercise_counts.fail_counts,
|
||||
pass_counts:data&&data.exercise_counts.pass_counts,
|
||||
good_counts:data&&data.exercise_counts.good_counts,
|
||||
best_counts:data&&data.exercise_counts.best_counts,
|
||||
})
|
||||
|
||||
|
||||
|
||||
let columns=[{
|
||||
title: '提交率',
|
||||
dataIndex: 'commit_percent',
|
||||
key: 'commit_percent',
|
||||
render: (text, record) => (
|
||||
<span style={{color:'#333333'}}>
|
||||
{record.commit_percent===0?0:(record.commit_percent*100).toFixed(2)}<span className={"font-size12"}>%</span>
|
||||
</span>
|
||||
),
|
||||
}, {
|
||||
title: '最低分',
|
||||
dataIndex: 'min_score',
|
||||
key: 'min_score',
|
||||
render: (text, record) => (
|
||||
<span>
|
||||
<span style={{color:'#333333'}}>{record.min_score}<span className={"font-size12"}>分</span></span>
|
||||
</span>
|
||||
),
|
||||
}, {
|
||||
title: '最高分',
|
||||
dataIndex: 'max_score',
|
||||
key: 'max_score',
|
||||
render: (text, record) => (
|
||||
<span style={{color:'#FF6800'}}>
|
||||
{record.max_score}<span className={"font-size12"}>分</span>
|
||||
</span>
|
||||
),
|
||||
}, {
|
||||
title: '平均分',
|
||||
key: 'average_score',
|
||||
dataIndex: 'average_score',
|
||||
|
||||
render: (text, record) => (
|
||||
<span style={{color:'#333333'}}>
|
||||
{record.average_score}<span className={"font-size12"}>分</span>
|
||||
</span>
|
||||
),
|
||||
}, {
|
||||
title: '不及格(0-60)',
|
||||
key: 'fail_counts',
|
||||
dataIndex: 'fail_counts',
|
||||
render: (text, record) => (
|
||||
<span style={{color:'#333333'}}>
|
||||
{record.fail_counts}<span className={"font-size12"}>人</span>
|
||||
</span>
|
||||
),
|
||||
}, {
|
||||
title: '及格(60-70)',
|
||||
key: 'pass_counts',
|
||||
dataIndex: 'pass_counts',
|
||||
|
||||
render: (text, record) => (
|
||||
<span style={{color:'#333333'}}>
|
||||
{record.pass_counts}<span className={"font-size12"}>人</span>
|
||||
</span>
|
||||
),
|
||||
}, {
|
||||
title: '良好(70-90)',
|
||||
key: 'good_counts',
|
||||
dataIndex: 'good_counts',
|
||||
|
||||
render: (text, record) => (
|
||||
<span>
|
||||
<span style={{color:'#333333'}}>{record.good_counts}<span className={"font-size12"}>人</span></span>
|
||||
</span>
|
||||
),
|
||||
}, {
|
||||
title: '优秀(90-100)',
|
||||
key: 'best_counts',
|
||||
dataIndex: 'best_counts',
|
||||
|
||||
render: (text, record) => (
|
||||
<span>
|
||||
<span style={{color:'#FF6800'}}>{record.best_counts}<span className={"font-size12"}>人</span></span>
|
||||
</span>
|
||||
),
|
||||
}];
|
||||
// {
|
||||
// title: '调分',
|
||||
// key: 'adjustmentminute',
|
||||
// dataIndex: 'adjustmentminute',
|
||||
//
|
||||
// render: (text, record) => (
|
||||
// <span>
|
||||
// <a>6小时 50分钟 6秒</a>
|
||||
// </span>
|
||||
// ),
|
||||
// },
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<div>
|
||||
{/*{data===undefined?"":""}*/}
|
||||
<style>{`
|
||||
.ant-table-thead > tr > th{
|
||||
text-align: center;
|
||||
}
|
||||
.tasknamebox{
|
||||
width: 50px;
|
||||
height: 24px;
|
||||
border: 1px solid rgba(221,23,23,1);
|
||||
border-radius: 12px;
|
||||
color: rgba(221,23,23,1);
|
||||
display: inline-block;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
.tasknameboxs{
|
||||
color: #666666 !important;
|
||||
background:rgba(237,237,237,1) !important;
|
||||
}
|
||||
|
||||
.ant-table-tbody > tr > td{
|
||||
font-size:14px;
|
||||
}
|
||||
.task-hide{
|
||||
max-width: 345px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.ant-table-tbody > tr{
|
||||
height:64px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
`}
|
||||
</style>
|
||||
{datas===undefined?"":<Table
|
||||
dataSource={datas}
|
||||
columns={columns}
|
||||
pagination={false}
|
||||
// loading={loadingstate}
|
||||
// onChange={this.TablePagination}
|
||||
/>}
|
||||
</div>
|
||||
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import React, {Component} from "react";
|
||||
import {WordsBtn} from 'educoder';
|
||||
import {Table} from "antd";
|
||||
import {Link,Switch,Route,Redirect} from 'react-router-dom';
|
||||
|
||||
class OfficialAcademicTranscript extends Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
loadingstate:true,
|
||||
datas:undefined
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
let {data}=this.props;
|
||||
let datas=[];
|
||||
// data&&data.exercise_counts.forEach((item,key)=>{ })
|
||||
|
||||
datas.push({
|
||||
commit_percent:data&&data.exercise_counts.commit_percent,
|
||||
min_score:data&&data.exercise_counts.min_score,
|
||||
max_score:data&&data.exercise_counts.max_score,
|
||||
average_score:data&&data.exercise_counts.average_score,
|
||||
fail_counts:data&&data.exercise_counts.fail_counts,
|
||||
pass_counts:data&&data.exercise_counts.pass_counts,
|
||||
good_counts:data&&data.exercise_counts.good_counts,
|
||||
best_counts:data&&data.exercise_counts.best_counts,
|
||||
})
|
||||
|
||||
|
||||
|
||||
let columns=[{
|
||||
title: '提交率',
|
||||
dataIndex: 'commit_percent',
|
||||
key: 'commit_percent',
|
||||
render: (text, record) => (
|
||||
<span style={{color:'#333333'}}>
|
||||
{record.commit_percent===0?0:(record.commit_percent*100).toFixed(2)}<span className={"font-size12"}>%</span>
|
||||
</span>
|
||||
),
|
||||
}, {
|
||||
title: '最低分',
|
||||
dataIndex: 'min_score',
|
||||
key: 'min_score',
|
||||
render: (text, record) => (
|
||||
<span>
|
||||
<span style={{color:'#333333'}}>{record.min_score}<span className={"font-size12"}>分</span></span>
|
||||
</span>
|
||||
),
|
||||
}, {
|
||||
title: '最高分',
|
||||
dataIndex: 'max_score',
|
||||
key: 'max_score',
|
||||
render: (text, record) => (
|
||||
<span style={{color:'#FF6800'}}>
|
||||
{record.max_score}<span className={"font-size12"}>分</span>
|
||||
</span>
|
||||
),
|
||||
}, {
|
||||
title: '平均分',
|
||||
key: 'average_score',
|
||||
dataIndex: 'average_score',
|
||||
|
||||
render: (text, record) => (
|
||||
<span style={{color:'#333333'}}>
|
||||
{record.average_score}<span className={"font-size12"}>分</span>
|
||||
</span>
|
||||
),
|
||||
}, {
|
||||
title: '不及格(0-60)',
|
||||
key: 'fail_counts',
|
||||
dataIndex: 'fail_counts',
|
||||
render: (text, record) => (
|
||||
<span style={{color:'#333333'}}>
|
||||
{record.fail_counts}<span className={"font-size12"}>人</span>
|
||||
</span>
|
||||
),
|
||||
}, {
|
||||
title: '及格(60-70)',
|
||||
key: 'pass_counts',
|
||||
dataIndex: 'pass_counts',
|
||||
|
||||
render: (text, record) => (
|
||||
<span style={{color:'#333333'}}>
|
||||
{record.pass_counts}<span className={"font-size12"}>人</span>
|
||||
</span>
|
||||
),
|
||||
}, {
|
||||
title: '良好(70-90)',
|
||||
key: 'good_counts',
|
||||
dataIndex: 'good_counts',
|
||||
|
||||
render: (text, record) => (
|
||||
<span>
|
||||
<span style={{color:'#333333'}}>{record.good_counts}<span className={"font-size12"}>人</span></span>
|
||||
</span>
|
||||
),
|
||||
}, {
|
||||
title: '优秀(90-100)',
|
||||
key: 'best_counts',
|
||||
dataIndex: 'best_counts',
|
||||
|
||||
render: (text, record) => (
|
||||
<span>
|
||||
<span style={{color:'#FF6800'}}>{record.best_counts}<span className={"font-size12"}>人</span></span>
|
||||
</span>
|
||||
),
|
||||
}];
|
||||
// {
|
||||
// title: '调分',
|
||||
// key: 'adjustmentminute',
|
||||
// dataIndex: 'adjustmentminute',
|
||||
//
|
||||
// render: (text, record) => (
|
||||
// <span>
|
||||
// <a>6小时 50分钟 6秒</a>
|
||||
// </span>
|
||||
// ),
|
||||
// },
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<div>
|
||||
{/*{data===undefined?"":""}*/}
|
||||
<style>{`
|
||||
.ant-table-thead > tr > th{
|
||||
text-align: center;
|
||||
}
|
||||
.tasknamebox{
|
||||
width: 50px;
|
||||
height: 24px;
|
||||
border: 1px solid rgba(221,23,23,1);
|
||||
border-radius: 12px;
|
||||
color: rgba(221,23,23,1);
|
||||
display: inline-block;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
.tasknameboxs{
|
||||
color: #666666 !important;
|
||||
background:rgba(237,237,237,1) !important;
|
||||
}
|
||||
|
||||
.ant-table-tbody > tr > td{
|
||||
font-size:14px;
|
||||
}
|
||||
.task-hide{
|
||||
max-width: 345px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.ant-table-tbody > tr{
|
||||
height:64px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.exerctabel .ant-table-tbody > tr >td{
|
||||
border:1px solid transparent;
|
||||
}
|
||||
|
||||
`}
|
||||
</style>
|
||||
{datas===undefined?"":<Table
|
||||
className={"exerctabel"}
|
||||
dataSource={datas}
|
||||
columns={columns}
|
||||
pagination={false}
|
||||
// loading={loadingstate}
|
||||
// onChange={this.TablePagination}
|
||||
/>}
|
||||
</div>
|
||||
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default OfficialAcademicTranscript;
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,158 @@
|
||||
import React, { Component } from "react";
|
||||
import { Modal, Checkbox, Input, Spin, Upload, Divider, Icon } from "antd";
|
||||
import axios from 'axios'
|
||||
import ModalWrapper from "../../common/ModalWrapper"
|
||||
|
||||
import { ConditionToolTip, getUploadActionUrl } from 'educoder'
|
||||
|
||||
const { Dragger } = Upload;
|
||||
|
||||
|
||||
|
||||
class CreateGroupByImportModal extends Component{
|
||||
constructor(props){
|
||||
super(props);
|
||||
this.state={
|
||||
}
|
||||
}
|
||||
fetchMemberList = (arg_page) => {
|
||||
}
|
||||
componentDidMount() {
|
||||
|
||||
|
||||
}
|
||||
onSendOk = () => {
|
||||
const courseId = this.props.match.params.coursesId
|
||||
|
||||
let url = `/courses/${courseId}/create_group_by_importing_file.json`
|
||||
let { fileList } =this.state;
|
||||
|
||||
if (!fileList || fileList.length == 0) {
|
||||
// this.props.showNotification('请先上传附件')
|
||||
this.setState({
|
||||
errorTip :'请先上传附件',
|
||||
})
|
||||
return;
|
||||
}
|
||||
let newfileList=[];
|
||||
for(var list of fileList){
|
||||
newfileList.push(list.response.id)
|
||||
}
|
||||
|
||||
axios.post(url, {
|
||||
attachment_ids: newfileList
|
||||
})
|
||||
.then((response) => {
|
||||
if (response.data.status == 0) {
|
||||
this.props.showNotification(response.data.message)
|
||||
this.setVisible(false)
|
||||
} else {
|
||||
|
||||
}
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
setVisible = (visible) => {
|
||||
if (visible) {
|
||||
this.setState({ fileList: [] });
|
||||
}
|
||||
this.refs.modalWrapper.setVisible(visible)
|
||||
|
||||
}
|
||||
handleChange = (info) => {
|
||||
let fileList = info.fileList;
|
||||
console.log(fileList)
|
||||
this.setState({ fileList });
|
||||
}
|
||||
|
||||
onOk = () => {
|
||||
this.onSendOk()
|
||||
}
|
||||
|
||||
onAttachmentRemove = (file) => {
|
||||
this.props.confirm({
|
||||
content: '是否确认删除?',
|
||||
|
||||
onOk: () => {
|
||||
this.deleteAttachment(file)
|
||||
},
|
||||
onCancel() {
|
||||
console.log('Cancel');
|
||||
},
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
deleteAttachment = (file) => {
|
||||
const url = `/attachments/${file.response ? file.response.id : file.uid}.json`
|
||||
axios.delete(url, {
|
||||
})
|
||||
.then((response) => {
|
||||
if (response.data) {
|
||||
// const { status } = response.data;
|
||||
if (response.data.status === 0) {
|
||||
|
||||
this.setState((state) => {
|
||||
const index = state.fileList.indexOf(file);
|
||||
const newFileList = state.fileList.slice();
|
||||
newFileList.splice(index, 1);
|
||||
return {
|
||||
fileList: newFileList,
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
|
||||
render(){
|
||||
const { candidates, checkBoxValues, loading, hasMore, name, school_name, school_names
|
||||
, graduationGroup, graduation_groups, courseGroup, course_groups } = this.state
|
||||
const { moduleName } = this.props
|
||||
|
||||
const props = {
|
||||
name: 'file',
|
||||
multiple: true,
|
||||
action: getUploadActionUrl(),
|
||||
onRemove: this.onAttachmentRemove,
|
||||
onChange: this.handleChange
|
||||
};
|
||||
return(
|
||||
<ModalWrapper
|
||||
ref="modalWrapper"
|
||||
width="700px"
|
||||
title={`导入创建分班`}
|
||||
{...this.props }
|
||||
onOk={this.onOk}
|
||||
className="createGroupByImport"
|
||||
>
|
||||
|
||||
<style>
|
||||
{`
|
||||
|
||||
`}
|
||||
</style>
|
||||
<div className="df">
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
<Dragger {...props}>
|
||||
<p className="ant-upload-drag-icon">
|
||||
<Icon type="inbox" />
|
||||
</p>
|
||||
<p className="ant-upload-text">点击或拖拽文件到这里上传</p>
|
||||
<p className="ant-upload-hint">
|
||||
单个文件最大150MB
|
||||
</p>
|
||||
</Dragger>
|
||||
</ModalWrapper>
|
||||
)
|
||||
}
|
||||
}
|
||||
export default CreateGroupByImportModal;
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue