课堂统计模块end

dev_auth
杨树明 5 years ago
parent 735ff5c517
commit e44dc226c7

@ -16,6 +16,7 @@
"babel-plugin-syntax-dynamic-import": "^6.18.0",
"babel-preset-react-app": "^3.1.1",
"babel-runtime": "6.26.0",
"bizcharts": "^3.5.5",
"bundle-loader": "^0.5.6",
"case-sensitive-paths-webpack-plugin": "2.1.1",
"chalk": "1.1.3",

@ -0,0 +1,123 @@
import React,{ Component } from "react";
import {Menu, Dropdown, Icon,Input,Checkbox} from "antd";
import {getImageUrl} from 'educoder';
const { Search } = Input;
class Dropdownbox extends Component{
constructor(props){
super(props);
this.state={
activeKey:'1',
visible: false,
onSearchvalue:undefined,
checkedValues:[]
}
}
componentDidMount() {
let {group_ids}=this.props;
if(group_ids){
this.setState({
checkedValues:group_ids
})
}
}
componentDidUpdate=(prevProps)=>{
if(prevProps!=this.props){
let {group_ids}=this.props;
if(group_ids){
this.setState({
checkedValues:group_ids
})
}
}
}
SaveChange=()=>{
this.props.postwork_scoredata(this.state.checkedValues)
}
handleVisibleChange=flag=>{
this.setState({ visible: flag });
};
CheckboxonChange=(checkedValues)=>{
this.setState({
checkedValues:checkedValues
})
}
unCheckboxonChange=()=>{
this.setState({
checkedValues:[],
onSearchvalue:undefined
})
}
onSearch=(value)=>{
this.setState({
onSearchvalue:value
})
}
onSearchonChange=(e)=>{
this.setState({
onSearchvalue:e.target.value
})
}
render(){
let {course_groups}=this.props;
const menu = (
<Checkbox.Group style={{ width: 220 }} className={"StatisticsMenubox"} value={this.state.checkedValues} onChange={(checkedValues)=>this.CheckboxonChange(checkedValues)}>
<Menu className="Statisticslibox">
<li className={"Statisticsli"}>
{course_groups&&course_groups.length>10?<Search
placeholder="请输入名称搜索"
onSearch={(value)=>this.onSearch(value)}
onChange={(e)=>this.onSearchonChange(e)}
value={this.state.onSearchvalue}
style={{ width: 200 }}
/>:""}
</li>
{course_groups&&course_groups.map((item,key)=>{
if(this.state.onSearchvalue){
if(item.name.indexOf(this.state.onSearchvalue) != -1){
return(
<Menu.Item key={key}>
<Checkbox value={item.id} key={item.id}> {item.name}</Checkbox>
</Menu.Item>
)
}
}else{
return(
<Menu.Item key={key}>
<Checkbox value={item.id} key={item.id}> {item.name}</Checkbox>
</Menu.Item>
)
}
})}
<Menu.Divider />
<li className={"Statisticsli"}>
<span onClick={()=>this.SaveChange()} className={"ant-btn-link"}>确定</span>
<span className={"ml20 ant-btn-link"} onClick={()=>this.unCheckboxonChange()}>重置</span>
</li>
</Menu>
</Checkbox.Group>
);
return(
<React.Fragment>
<Dropdown overlay={menu}
onVisibleChange={this.handleVisibleChange}
visible={this.state.visible}
>
<a className="ant-dropdown-link">
分班 <Icon type="down" />
</a>
</Dropdown>
</React.Fragment>
)
}
}
export default Dropdownbox;

@ -0,0 +1,90 @@
import React,{ Component } from "react";
import {Row, Col,Popover,Button,Icon} from "antd";
import {
G2,
Chart,
Geom,
Axis,
Tooltip,
Coord,
Label,
Legend,
View,
Guide,
Shape,
Facet,
Util
} from "bizcharts";
class Dynamiclist extends Component{
constructor(props){
super(props);
this.state={
}
}
render(){
const data = []
let {course_members}=this.props;
if(course_members){
if(course_members.length>0){
course_members.map((item,key)=>{
data.push({'name':item.user_name,'活跃度':item.total_score})
})
}
}
const content = (
<div className={"Statisticscircle"}>
<p>
作业完成数*10
</p>
<p>
试卷完成数*10
</p>
<p>
问卷完成数*7
</p>
<p>
资源发布数*5
</p>
<p>
帖子发布数*2
</p>
<p>
帖子回复数*1
</p>
<p>
作业回复数*1
</p>
</div>
);
return(
<React.Fragment>
<Row>
<Col span={12} className={"top10s"}>Top 10</Col>
<Col span={12} className={"Statisticsliboxjsgz"}>
<span className={"mr10"}>计算规则</span>
<Popover placement="bottom" content={content} trigger="hover">
<Icon type="exclamation-circle" />
</Popover>
</Col>
</Row>
{/*scale={cols}*/}
<Chart height={400} data={data} forceFit>
<Axis name="name" />
<Axis name="活跃度" />
<Tooltip
crosshairs={{
type: "y"
}}
/>
<Geom type="interval" position="name*活跃度" />
</Chart>
</React.Fragment>
)
}
}
export default Dynamiclist;

@ -63,5 +63,65 @@
text-align: center;
line-height: 61px;
font-size: 16px;
color: rgba(80,145,255,1);
}
.Statisticsli{
clear: both;
margin: 0;
padding: 5px 12px;
color: rgba(0, 0, 0, 0.65);
font-weight: normal;
font-size: 14px;
line-height: 22px;
white-space: nowrap;
cursor: pointer;
-webkit-transition: all 0.3s;
-o-transition: all 0.3s;
transition: all 0.3s;
}
.StatisticsMenubox{
position: relative;
margin: 0;
padding: 4px 0;
text-align: left;
list-style-type: none;
background-color: #fff;
background-clip: padding-box;
border-radius: 4px;
outline: none;
-webkit-box-shadow: 0 2px 8px rgba(0,0,0,0.15);
box-shadow: 0 2px 8px rgba(0,0,0,0.15);
-webkit-transform: translate3d(0, 0, 0);
}
.Statisticslibox li label{
width: 200px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.Statisticslibox .ant-menu-item{
height: 20px;
line-height: 20px;
text-overflow: clip;
}
.top10s{
font-size: 16px;
font-weight: bold;
color: rgba(51,51,51,1);
}
.Statisticsliboxjsgz{
font-size:12px;
color:rgba(51,51,51,1);
text-align: right;
}
.Statisticscircle p{
height: 30px;
font-size: 12px;
color: rgba(153,153,153,1);
line-height: 30px;
}

@ -1,8 +1,9 @@
import React,{ Component } from "react";
import {Table, Pagination,Tooltip,Spin, Row, Col ,Tabs} from "antd";
import { WordsBtn,on, off, trigger ,getImageUrl} from 'educoder';
import {BrowserRouter as Router,Route,Switch,Link} from 'react-router-dom';
import {Table, Pagination,Tooltip,Spin, Row, Col ,Checkbox,Tabs,Menu, Dropdown, Icon,Input} from "antd";
import { WordsBtn,on, off, trigger ,getImageUrl,sortDirections} from 'educoder';
import axios from'axios';
import Dropdownbox from './Dropdownbox';
import Dynamiclist from './Dynamiclist';
import './Statistics.css';
const { TabPane } = Tabs;
class Statistics extends Component{
@ -18,20 +19,29 @@ class Statistics extends Component{
bomisSpin:true,
sort:'desc',
course_groups:[],
page:1
page:1,
all_count:null,
activeKey:'1',
visible: false,
group_ids:[],
course_members:[]
}
}
componentDidMount() {
let {page,group_ids,sort}=this.state;
this.getdatas()
}
getdatas=()=>{
let {page,group_ids,sort}=this.state;
let courseId=this.props.match.params.coursesId;
let url=`/courses/${courseId}/statistics.json`;
axios.get(url).then((result) => {
if (result) {
this.setState({
data:result.data.top_scores,
topisSpin:false
})
this.setState({
data:result.data.top_scores,
topisSpin:false
})
}
}).catch((error) => {
console.log(error);
@ -39,8 +49,6 @@ class Statistics extends Component{
topisSpin:false,
})
})
let courseurl=`/courses/${courseId}/all_course_groups.json`;
axios.get(courseurl).then((result) => {
if (result) {
@ -57,11 +65,43 @@ class Statistics extends Component{
}
}).catch((error) => {
console.log(error);
})
}
getDynamiclistdatas=(group_ids)=>{
let courseId=this.props.match.params.coursesId;
let url=`/courses/${courseId}/act_score.json`;
let data={
group_ids:group_ids,
}
axios.get(url,{params:
data
}).then((result) => {
if (result) {
this.setState({
course_members:result.data.course_members,
bomisSpin:false
})
}
}).catch((error) => {
console.log(error);
this.setState({
bomisSpin:false,
})
})
}
getwork_scoredata=(page,group_ids,sort)=>{
let {activeKey}=this.state;
this.setState({
page:page,
sort:sort,
group_ids:group_ids,
bomisSpin:true,
})
if(activeKey==='1'){
let courseId=this.props.match.params.coursesId;
let url=`/courses/${courseId}/work_score.json`;
let data={
@ -76,6 +116,7 @@ class Statistics extends Component{
if (result) {
this.setState({
bomdata:result.data.course_members,
all_count:result.data.all_count,
bomisSpin:false
})
}
@ -85,63 +126,196 @@ class Statistics extends Component{
bomisSpin:false,
})
})
}else{
this.getDynamiclistdatas(group_ids)
}
}
callback=(key)=>{
console.log(key);
activeKey=(key)=>{
if(key==="1"){
this.getdatas()
}else{
let{group_ids}=this.state;
this.getDynamiclistdatas(group_ids)
}
this.setState({
activeKey:key
})
}
PaginationCourse=(pageNumber)=>{
let {group_ids,sort}=this.state;
this.getwork_scoredata(pageNumber,group_ids,sort);
}
derivefun=(url)=>{
let{group_ids}=this.state;
let data={
group_id:group_ids
}
axios.get(url,{params:
data
}).then((response)=>{
if(response === undefined){
return
}
if(response.data.status&&response.data.status===-1){
this.props.showNotification(response.data.message);
}else if(response.data.status&&response.data.status===-2){
// if(response.data.message === "100"){
// // 已超出文件导出的上限数量100 ),建议:
//
// this.setState({
// DownloadType:true,
// DownloadMessageval:100
// })
// }else {
// //因附件资料超过500M
// this.setState({
// DownloadType:true,
// DownloadMessageval:500
// })
// }
this.props.showNotification(response.data.message);
}else {
// this.props.showNotification(`正在下载中`);
// window.open("/api"+url, '_blank');
this.props.slowDownload(url);
}
}).catch((error) => {
console.log(error)
});
}
// 筛选
handleTableChange =(pagination, filters, data)=>{
let order=data.order;
let {page,group_ids}=this.state;
if(order==="descend"){
this.getwork_scoredata(page,group_ids,'desc')
}else{
this.getwork_scoredata(page,group_ids,'asc')
}
}
render(){
let {nd1,nd2,nd3,data,bomdata,course_groups}=this.state;
let course_grouptype=false
if(this.props&&this.props.course_modules!=undefined){
let {nd1,nd2,nd3,data,bomdata}=this.state;
const columns = [
{
title: this.props.isAdmin()===true?'序号':'排名',
dataIndex: 'index',
render: (text, record,index) => {
return this.props.isAdmin()===true?(this.state.page - 1) * 20 + index + 1:record.rank
}
},
{
title: '姓名',
dataIndex:'user_name',
render: (text, record) => (
<span>{record.user_name}</span>
)
},
{
title: '分班',
dataIndex: 'course_group',
render: (text, record) => (
<span >{record.course_group}</span>
)
},
{
title: '实训作业',
dataIndex: 'practice_score',
render: (text, record) => (
<span >{record.practice_score.toFixed(2)}</span>
)
},
{
title: '普通作业',
dataIndex: 'common_score',
render: (text, record) => (
<span >{record.common_score.toFixed(2)}</span>
)
},
{
title: '分组作业',
dataIndex: 'group_score',
render: (text, record) => (
<span >{record.group_score.toFixed(2)}</span>
)
},
{
title: '毕设任务',
dataIndex: 'graduation_score',
render: (text, record) => (
<span >{record.graduation_score.toFixed(2)}</span>
)
},
{
title: '试卷',
dataIndex: 'exercise_score',
render: (text, record) => (
<span >{record.exercise_score}</span>
)
},
{
title: '总成绩',
dataIndex: 'total_score',
sorter: this.props.isAdmin()===true?true:false,
defaultSortOrder: 'descend',
sortDirections: sortDirections,
render: (text, record) => (
<span >{record.total_score.toFixed(2)}</span>
)
},
];
let course_grouptype=false;
if(this.props&&this.props.course_modules!=undefined){
{this.props&&this.props.course_modules.map((item,key)=>{
if(item.type==="course_group"){
course_grouptype=true
}
})}
}
// const columns = [
// {
// title: 'Name',
// dataIndex: 'name',
// sorter: true,
// render: name => `${name.first} ${name.last}`,
// width: '20%',
// },
// {
// title: 'Gender',
// dataIndex: 'gender',
// filters: course_groups,
// width: '20%',
// },
// {
// title: 'Email',
// dataIndex: 'email',
// },
// ];
// console.log(bomdata)
//common_score: 0
// course_group: "威风威风急急急"
// exercise_score: "0.0"
// graduation_score: 0
// group_score: 0
// practice_score: 3232
// total_score: 3232
// user_login: "p40793521"
// user_name: "李明霞"
if(course_grouptype===false){
columns.some((item,key)=> {
if (item.title === "分班") {
columns.splice(key, 1)
return true
}
}
)
}
// console.log(this.props.isAdmin)
// "user_login": "p94602358",
// "user_name": "卿前程",
// "course_group": "电气工程1805", // 分班
// "common_score": 0.0, // 普通作业
// "group_score": 0.0, // 分组作业
// "practice_score": 747.1000061035156, // 实训作业
// "exercise_score": 0.0, // 试卷成绩
// "graduation_score": 0.0, // 毕设成绩
// "total_score": 747.1000061035156, // 总成绩
// "rank": 1 // 排名,学生身份才传
const operations = <React.Fragment>
<Dropdownbox
{...this.props}
{...this.state}
postwork_scoredata={(group_idss)=>this.getwork_scoredata(1,group_idss,'desc')}
/>
<a className={"ml20 ant-btn-link"} onClick={()=>this.derivefun(`/courses/${this.props.match.params.coursesId}/export_member_scores_excel.xlsx`)}>导出</a>
</React.Fragment>;
return(
<React.Fragment >
<div>
<React.Fragment>
<div className="edu-back-white">
<Spin size="large" spinning={this.state.topisSpin}>
<p className="clearfix padding30">
@ -301,22 +475,53 @@ class Statistics extends Component{
<div className="mt20 edu-back-white">
<Spin size="large" spinning={this.state.bomisSpin}>
<Tabs className="statisticsTabs" defaultActiveKey="1" onChange={this.callback}>
<TabPane tab="学习成绩" key="1" className={"statisticsTabs1"}>
{/*<Table*/}
{/*columns={columns}*/}
{/*dataSource={bomdata}*/}
{/*onChange={this.handleTableChange}*/}
{/*/>*/}
<style>{
`
.ant-select-dropdown-menu {
max-height: 320px;
}
.ant-tabs-extra-content{
margin-top:20px;
}
.ant-table-thead > tr > th, .ant-table-tbody > tr > td {
padding: 16px 0px;
}
`
}</style>
<Tabs className="statisticsTabs" activeKey={this.state.activeKey} onChange={this.activeKey} tabBarExtraContent={this.props.isAdmin()===true?operations:""}>
<TabPane tab="学习成绩" key="1" className={"statisticsTabs1"} >
<Table
columns={columns}
dataSource={bomdata}
pagination={false}
onChange={this.handleTableChange}
/>
</TabPane>
<TabPane tab="课堂活跃度" key="2">
Content of Tab Pane 2
<Dynamiclist
{...this.state}
{...this.props}
/>
</TabPane>
</Tabs>
</Spin>
</div>
</div>
{this.state.all_count===undefined||this.state.all_count===null||this.state.activeKey==="2"?'':this.state.all_count >20&&this.props.isAdmin()===true?<div className="mb40 edu-txt-center padding20-30"
>
<Pagination
showQuickJumper
defaultCurrent={1}
pageSize={20}
total={this.state.all_count===undefined?0:this.state.all_count===null?0:this.state.all_count}
current={this.state.page}
onChange={this.PaginationCourse}
/>
</div>:""}
</React.Fragment>
)
}

Loading…
Cancel
Save