diff --git a/public/react/package.json b/public/react/package.json index ac239dd0f..5bc10f627 100644 --- a/public/react/package.json +++ b/public/react/package.json @@ -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", diff --git a/public/react/src/modules/courses/statistics/Dropdownbox.js b/public/react/src/modules/courses/statistics/Dropdownbox.js new file mode 100644 index 000000000..548715993 --- /dev/null +++ b/public/react/src/modules/courses/statistics/Dropdownbox.js @@ -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 = ( + this.CheckboxonChange(checkedValues)}> + +
  • + {course_groups&&course_groups.length>10?this.onSearch(value)} + onChange={(e)=>this.onSearchonChange(e)} + value={this.state.onSearchvalue} + style={{ width: 200 }} + />:""} +
  • + {course_groups&&course_groups.map((item,key)=>{ + if(this.state.onSearchvalue){ + if(item.name.indexOf(this.state.onSearchvalue) != -1){ + return( + + {item.name} + + ) + } + }else{ + return( + + {item.name} + + ) + } + })} + +
  • + this.SaveChange()} className={"ant-btn-link"}>确定 + this.unCheckboxonChange()}>重置 +
  • +
    +
    + ); + + return( + + + + 分班 + + + + ) + } +} +export default Dropdownbox; diff --git a/public/react/src/modules/courses/statistics/Dynamiclist.js b/public/react/src/modules/courses/statistics/Dynamiclist.js new file mode 100644 index 000000000..0ea6eac1b --- /dev/null +++ b/public/react/src/modules/courses/statistics/Dynamiclist.js @@ -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 = ( +
    +

    + 作业完成数(*10) +

    +

    + 试卷完成数(*10) +

    +

    + 问卷完成数(*7) +

    +

    + 资源发布数(*5) +

    +

    + 帖子发布数(*2) +

    +

    + 帖子回复数(*1) +

    +

    + 作业回复数(*1) +

    +
    + ); + return( + + + Top 10 + + 计算规则 + + + + + + {/*scale={cols}*/} + + + + + + + + ) + } +} +export default Dynamiclist; diff --git a/public/react/src/modules/courses/statistics/Statistics.css b/public/react/src/modules/courses/statistics/Statistics.css index 686abd52e..cfae65597 100644 --- a/public/react/src/modules/courses/statistics/Statistics.css +++ b/public/react/src/modules/courses/statistics/Statistics.css @@ -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; } \ No newline at end of file diff --git a/public/react/src/modules/courses/statistics/Statistics.js b/public/react/src/modules/courses/statistics/Statistics.js index c4d5ddfa6..cb5cf9574 100644 --- a/public/react/src/modules/courses/statistics/Statistics.js +++ b/public/react/src/modules/courses/statistics/Statistics.js @@ -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) => ( + {record.user_name} + ) + }, + { + title: '分班', + dataIndex: 'course_group', + render: (text, record) => ( + {record.course_group} + ) + }, + { + title: '实训作业', + dataIndex: 'practice_score', + render: (text, record) => ( + {record.practice_score.toFixed(2)} + ) + }, + { + title: '普通作业', + dataIndex: 'common_score', + render: (text, record) => ( + {record.common_score.toFixed(2)} + ) + }, + { + title: '分组作业', + dataIndex: 'group_score', + render: (text, record) => ( + {record.group_score.toFixed(2)} + ) + }, + { + title: '毕设任务', + dataIndex: 'graduation_score', + render: (text, record) => ( + {record.graduation_score.toFixed(2)} + ) + }, + { + title: '试卷', + dataIndex: 'exercise_score', + render: (text, record) => ( + {record.exercise_score} + ) + }, + { + title: '总成绩', + dataIndex: 'total_score', + sorter: this.props.isAdmin()===true?true:false, + defaultSortOrder: 'descend', + sortDirections: sortDirections, + render: (text, record) => ( + {record.total_score.toFixed(2)} + ) + }, + ]; + + 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 = + this.getwork_scoredata(1,group_idss,'desc')} + /> + this.derivefun(`/courses/${this.props.match.params.coursesId}/export_member_scores_excel.xlsx`)}>导出 + ; return( - -
    - +

    @@ -301,22 +475,53 @@ class Statistics extends Component{

    - - - {/**/} + + + + - Content of Tab Pane 2 + - + {this.state.all_count===undefined||this.state.all_count===null||this.state.activeKey==="2"?'':this.state.all_count >20&&this.props.isAdmin()===true?
    + + + +
    :""} + ) }