diff --git a/public/react/src/modules/courses/shixunHomework/Listofworksstudentone.js b/public/react/src/modules/courses/shixunHomework/Listofworksstudentone.js
index d83f51c0a..cd8061906 100644
--- a/public/react/src/modules/courses/shixunHomework/Listofworksstudentone.js
+++ b/public/react/src/modules/courses/shixunHomework/Listofworksstudentone.js
@@ -461,7 +461,7 @@ class Listofworksstudentone extends Component {
)
},
{
- title: '当前成绩',
+ title:'当前成绩',
dataIndex: 'work_score',
key: 'work_score',
align: "center",
@@ -856,7 +856,7 @@ class Listofworksstudentone extends Component {
)
},
{
- title: '当前成绩',
+ title:'当前成绩',
dataIndex: 'work_score',
key: 'work_score',
align: "center",
@@ -1061,14 +1061,14 @@ class Listofworksstudentone extends Component {
}>
{record.cost_time === null ? "--" : record.cost_time === undefined ? "--" : record.cost_time === "--" ? "--" :
- {record.cost_time === null ? "--" : record.cost_time === undefined ? "--" : record.cost_time}
-
+
}
// 当前成绩
+ 鼠标停留具体分值上可查
+ 看得分明细
+ }>
,
dataIndex: 'work_score',
key: 'work_score',
align: 'center',
@@ -1300,7 +1303,7 @@ class Listofworksstudentone extends Component {
// onClick={() => this.Viewstudenttraininginformationt(record)}
>{record.has_comment===true?"详情":"评阅 "} :
- this.Viewstudenttraininginformationtysl2(e, record)}
// onClick={() => this.Viewstudenttraininginformationt(record)}
>{record.has_comment===true?"详情":"评阅 "}
@@ -1446,14 +1449,14 @@ class Listofworksstudentone extends Component {
}
}>
{record.cost_time === null ? "--" : record.cost_time === undefined ? "--" : record.cost_time === "--" ? "--" :
- {record.cost_time === null ? "--" : record.cost_time === undefined ? "--" : record.cost_time}
-
+
}
)
@@ -1569,7 +1572,10 @@ class Listofworksstudentone extends Component {
)
},
{
- title: '当前成绩',
+ title: 当前成绩
+ 鼠标停留具体分值上可查
+ 看得分明细
+ }>
,
dataIndex: 'work_score',
key: 'work_score',
align: 'center',
diff --git a/public/react/src/modules/courses/shixunHomework/Trainingjobsetting.js b/public/react/src/modules/courses/shixunHomework/Trainingjobsetting.js
index a6cefb466..e14ad1408 100644
--- a/public/react/src/modules/courses/shixunHomework/Trainingjobsetting.js
+++ b/public/react/src/modules/courses/shixunHomework/Trainingjobsetting.js
@@ -135,6 +135,8 @@ class Trainingjobsetting extends Component {
borredszfls:'',
total_scoretwo:0,
total_score:0,
+ immediatelyopen:false,
+ modallate_time:undefined
}
// console.log("获取到的值")
// console.log("Trainingjobsetting")
@@ -1757,7 +1759,9 @@ class Trainingjobsetting extends Component {
Savesname: "立即发布",
Cancel: this.homeworkhide,
Saves: this.homeworkstartend,
- course_groups: response.data.course_groups,
+ course_groups:response.data.course_groups,
+ immediatelyopen:true,
+ modallate_time:response.data.late_time,
})
}
}).catch((error) => {
@@ -1799,6 +1803,7 @@ class Trainingjobsetting extends Component {
}
// 立即发布
homeworkstartend = (ds, endtime) => {
+ debugger
var homeworkid = this.props.match.params.homeworkid;
let data = {}
@@ -1914,6 +1919,8 @@ class Trainingjobsetting extends Component {
typs: undefined,
starttimes: undefined,
starttimesend: undefined,
+ immediatelyopen:false,
+ modallate_time:undefined,
})
}
cancelBox = () => {
@@ -2401,6 +2408,8 @@ class Trainingjobsetting extends Component {
starttimes={this.state.starttimes}
starttimesend={this.state.starttimesend}
typs={this.state.typs}
+ immediatelyopen={this.state.immediatelyopen}
+ modallate_time={this.state.modallate_time}
/> : ""}
{
+
+ const coursesId=this.props.match.params.coursesId;
+ let url=`/weapps/courses/${coursesId}/attendances.json`
+ axios.get(url,{params:{
+ group_id:group_id==="全部"?undefined:group_id
+ }
+ }).then((response) => {
+
+ if(response){
+ if(response.data){
+ let newlists=[]
+
+ if(response.data.history_attendances.length>0){
+ response.data.history_attendances.map((item,key)=>{
+ newlists.push({
+ month: item.index,
+ name: item.name+" "+item.attendance_date+" "+item.start_time+"-"+item.end_time,
+ // month:item.name,
+ city:"到课率",
+ temperature: (item.normal_rate*100).toFixed(0)
+ })
+ newlists.push({
+ month: item.index,
+ name: item.name+" "+item.attendance_date+" "+item.start_time+"-"+item.end_time,
+ // month:item.name,
+ city: "旷课率",
+ temperature: (item.absence_rate*100).toFixed(0)
+ })
+ newlists.push({
+ month: item.index,
+ name: item.name+" "+item.attendance_date+" "+item.start_time+"-"+item.end_time,
+ // month:item.name,
+ city: "请假率",
+ temperature: (item.leave_rate*100).toFixed(0)
+ })
+ })
+ }
+
+ this.setState({
+ datas:response.data,
+ newlist:newlists
+ })
+
+
+ }
+ }
+ this.setState({
+ spal:false
+ })
+ }).catch((error) => {
+ this.setState({
+ spal:false
+ })
+
+ })
+ }
+
+ componentDidMount() {
+ this.setState({
+ spal:true
+ })
+ const coursesId=this.props.match.params.coursesId;
+ let newurl=`/courses/${coursesId}/all_course_groups.json`;
+ axios.get(newurl).then((response) => {
+ let newlist=this.state.course_groups;
+ response.data.course_groups.map((item,key)=>{
+ newlist.push(item)
+ })
+ this.setState({
+ course_groups:newlist
+ })
+ })
+
+ this.getdata()
+ }
+
+ handleChange=(value)=>{
+ this.getdata(value)
+ }
+
+ render() {
+ let {datas,newlist,course_groups,spal}=this.state;
+
+ const cols = {
+ month: {
+ type: 'pow',
+ // nice: true,
+ exponent:1,
+ // minLimit:1,
+ // tickInterval:1,
+ // minTickInterval:2
+ },
+ temperature:{
+ type: 'linear',
+ nice:[0,100],
+ minTickInterval:2
+ }
+ };
+
+
+ return(
+
+
+ {
+ spal===true?
+
+
+
+
+ :
+
+
+
+
+
+
+ {datas&&datas.all_history_count}
+
+
+
+
+ {datas?(datas&&datas.avg_normal_rate*100).toFixed(0)+"%":""}
+
+
+
+
+ {datas?(datas&&datas.avg_absence_rate*100).toFixed(0)+"%":""}
+
+
+
+
+ {datas?(datas&&datas.avg_leave_rate*100).toFixed(0)+"%":""}
+
+
+
+
+ {newlist&&newlist.length>0?
+
+
+
+
+
+
+
+ 到课率
+
+
+
+
+
+ 旷课率
+
+
+
+
+
+ 请假率
+
+
+
+
+
+ 显示最近十次签到
+
+
+
+
+
+
+
+
+
+ {/**/}
+
+ `${val}%`
+ }}
+ />
+
+ {
+ return {
+ //自定义 tooltip 上显示的 title 显示内容等。
+ name: city,
+ title: name,
+ value: temperature+"%"
+ };
+ }]}
+ />
+ {
+ // return {
+ // //自定义 tooltip 上显示的 title 显示内容等。
+ // name: 'sold1',
+ // title: 'dddd' + month,
+ // value: temperature
+ // };
+ // }]}
+ />
+
+
+
+
:
+
+
}
+
+ }
+
+
+
+
+ )
+ }
+
+}
+
+
+
+
+
+
+export default Signinstatistics;
diff --git a/public/react/src/modules/courses/signin/component/Detailss.js b/public/react/src/modules/courses/signin/component/Detailss.js
new file mode 100644
index 000000000..c1f43e0cf
--- /dev/null
+++ b/public/react/src/modules/courses/signin/component/Detailss.js
@@ -0,0 +1,197 @@
+import React, {Component} from "react";
+import '../css/signincdi.css';
+import {Progress, message} from 'antd';
+import QRCode from 'qrcode.react';
+import axios from 'axios';
+
+function clearSlct() {
+ if ("getSelection" in window) {
+ window.getSelection().removeAllRanges();
+ } else {
+ document.selection.empty();
+ }
+ ;
+}
+
+function jsCopy(s) {
+ clearSlct();
+ const copyEle = document.getElementById(s);
+ copyEle.select();
+ const copyStatus = document.execCommand("Copy");
+ // 对成功与否定进行提示
+ copyStatuss(copyStatus)
+}
+
+function copyStatuss(copyStatus) {
+ if (copyStatus) {
+ message.success('复制成功');
+ } else {
+ message.error('复制失败');
+ }
+}
+
+//条目
+class Detailss extends Component {
+ //条目组件
+ constructor(props) {
+ super(props);
+
+ this.state = {}
+ }
+
+ componentDidMount() {
+
+ }
+
+ componentDidUpdate = (prevProps) => {
+
+
+ }
+
+
+ render() {
+ const isAdmin = this.props.isAdmin();
+ let item = this.props.headdata;
+ let defaultActiveKey = this.props.defaultActiveKey;
+ let jdt;
+ try {
+ jdt = item.normal_count / item.all_count * 100;
+ } catch (e) {
+ jdt = 100;
+ }
+ return (
+
+
+
+
+ {item && item.name}
+
+
+
+
+ 签到人数:
+
+
+
+ 已签到 {item && item.normal_count ? item.normal_count : 0} /
+ 应签到 {item && item.all_count ? item.all_count : 0}
+
+
+
+
+
+
+
+
+
+ 签到发起人:
+
+
+ {item && item.author.user_name}
+
+
+
+ 签到方式:
+
+
+ {item && item.mode ?
+ item.mode === "QRCODE" ?
+ "二维码签到"
+ : item.mode === "NUMBER" ?
+ "数字签到"
+ : item.mode === "QUICK" ?
+ "快捷签到"
+ : ""
+ : ""}
+
+
+
+ 开始结束时间:
+
+
+ {item && item.attendance_date} {item && item.start_time}-{item && item.end_time}
+
+
+ {
+ defaultActiveKey === "1" ?
+
+ {
+ item && item.mode === "NUMBER" ?
+
+
{
+ jsCopy("file_path" + 1)
+ }}>
+ 复制签到码
+
+
+ {item&&item.code}
+
+
签到码:
+
+
+
+
+ :
+ item && item.mode === "QRCODE" ?
+
+
+ : ""
+ }
+
+
+
+
+ :
+ ""
+ }
+
+
+
+
+
+
+
+ )
+ }
+}
+
+export default Detailss;
diff --git a/public/react/src/modules/courses/signin/component/NoneDatas.js b/public/react/src/modules/courses/signin/component/NoneDatas.js
new file mode 100644
index 000000000..c36cc29d1
--- /dev/null
+++ b/public/react/src/modules/courses/signin/component/NoneDatas.js
@@ -0,0 +1,36 @@
+import React, { Component } from 'react';
+import { getImageUrl , getUrl } from 'educoder';
+
+class NoneDatas extends Component{
+ constructor(props) {
+ super(props)
+ }
+ render(){
+ const { style } = this.props;
+ return(
+
+
+
}/)
+
暂无相关数据
+
+ )
+ }
+}
+export default NoneDatas;
diff --git a/public/react/src/modules/courses/signin/component/Teacherentry.js b/public/react/src/modules/courses/signin/component/Teacherentry.js
new file mode 100644
index 000000000..ff08fe126
--- /dev/null
+++ b/public/react/src/modules/courses/signin/component/Teacherentry.js
@@ -0,0 +1,174 @@
+import React, {Component} from "react";
+import '../css/signincdi.css';
+import {Progress} from 'antd';
+import axios from 'axios';
+
+//条目
+class Teacherentry extends Component {
+ //条目组件
+ constructor(props) {
+ super(props);
+
+ this.state = {}
+ }
+
+ componentDidMount() {
+
+ }
+
+ componentDidUpdate = (prevProps) => {
+
+
+ }
+
+
+ render() {
+ let isAdmin = this.props.isAdmin();
+ let item = this.props.item;
+ let index =this.props.index;
+ let jdt;
+ try {
+ jdt = item.normal_count / item.all_count * 100;
+ } catch (e) {
+ jdt = 100;
+ }
+ return (
+
+
+
{e.stopPropagation();this.props.qiandaoxiangq(true,item.id)}:""}>
+
+ {
+ item.name
+ }
+
+
+
+
+
+ 签到人数:
+
+
+
+ 已签到 {item.normal_count ? item.normal_count : 0} / 应签到 {item.all_count ? item.all_count : 0}
+
+
+
+
+
+
+
+
+
+ 签到发起人:
+
+
+ {item.author.user_name}
+
+
+
+ 签到方式:
+
+
+ {item.mode ?
+ item.mode === "QRCODE" ?
+ "二维码签到"
+ : item.mode === "NUMBER" ?
+ "数字签到"
+ : item.mode === "QUICK" ?
+ "快捷签到"
+ : ""
+ : ""}
+
+
+
+ 开始结束时间:
+
+
+ {item.attendance_date} {item.start_time}-{item.end_time}
+
+
+
+
+ {
+ isAdmin === true ?
+ this.props.defaultActiveKey === "1" ?
+
+
{e.stopPropagation();this.props.thisEnd(item.id)}}>截止
+
{e.stopPropagation();this.props.thisdelete(item.id)}}>删除
+
+ :
+ item.edit_auth === true ?
+
+
{e.stopPropagation();this.props.Signinnamestypes(item.id,true,item.name)}}>编辑
+
{e.stopPropagation();this.props.thisdelete(item.id)}}>删除
+
+ :
+
+
{e.stopPropagation();this.props.thisdelete(item.id)}}>删除
+
+ :
+ (
+ this.props.defaultActiveKey === "1" ?
+
+ {
+ item.attendance_status?
+ (
+ item.attendance_status==="ABSENCE"?
+
{e.stopPropagation();this.props.Signin(item.mode,item.id,item.attendance_code)}}>
+ 签到
+
+ :
+ item.attendance_status==="NORMAL"?
+
+ 正常签到
+
+ :""
+ )
+ :
+ ""
+ }
+
+
+ :
+
+ {
+ item.attendance_status?
+ item.attendance_status === "NORMAL" ?
+
+ 正常签到
+
+ : item.attendance_status === "LEAVE" ?
+
+ 请假
+
+ : item.attendance_status === "ABSENCE" ?
+
+ 旷课
+
+ :
+ ""
+ :
+ ""
+ }
+
+
+
+
+
+ )
+
+ }
+
+
+
+
+
+
+
+ )
+ }
+}
+
+export default Teacherentry;
diff --git a/public/react/src/modules/courses/signin/component/teachercomponent/Histeacomponent.js b/public/react/src/modules/courses/signin/component/teachercomponent/Histeacomponent.js
new file mode 100644
index 000000000..c5b2062f5
--- /dev/null
+++ b/public/react/src/modules/courses/signin/component/teachercomponent/Histeacomponent.js
@@ -0,0 +1,33 @@
+import React,{ Component } from "react";
+import '../../css/signincdi.css';
+//在线学习
+class Histeacomponent extends Component{
+ //教师历史签到
+ constructor(props){
+ super(props);
+
+ this.state={
+
+ }
+ }
+
+ componentDidMount() {
+
+ }
+
+ componentDidUpdate = (prevProps) => {
+
+
+ }
+
+
+
+ render(){
+ return(
+
+
+
+ )
+ }
+}
+export default Histeacomponent;
diff --git a/public/react/src/modules/courses/signin/component/teachercomponent/Signteacomponent.js b/public/react/src/modules/courses/signin/component/teachercomponent/Signteacomponent.js
new file mode 100644
index 000000000..2507c6d1e
--- /dev/null
+++ b/public/react/src/modules/courses/signin/component/teachercomponent/Signteacomponent.js
@@ -0,0 +1,33 @@
+import React,{ Component } from "react";
+import '../../css/signincdi.css';
+//在线学习
+class Signteacomponent extends Component{
+ //教师签到统计
+ constructor(props){
+ super(props);
+
+ this.state={
+
+ }
+ }
+
+ componentDidMount() {
+
+ }
+
+ componentDidUpdate = (prevProps) => {
+
+
+ }
+
+
+
+ render(){
+ return(
+
+
+
+ )
+ }
+}
+export default Signteacomponent;
diff --git a/public/react/src/modules/courses/signin/component/teachercomponent/Teaccomponent.js b/public/react/src/modules/courses/signin/component/teachercomponent/Teaccomponent.js
new file mode 100644
index 000000000..099625aaf
--- /dev/null
+++ b/public/react/src/modules/courses/signin/component/teachercomponent/Teaccomponent.js
@@ -0,0 +1,200 @@
+import React,{ Component } from "react";
+import '../../css/signincdi.css';
+import axios from 'axios';
+import Teacherentry from "../Teacherentry";
+import NoneDatas from '../NoneDatas';
+import LoadingSpin from '../../../../../common/LoadingSpin';
+import { Modal, Button } from 'antd';
+
+const { confirm } = Modal;
+
+//在线学习
+class Teaccomponent extends Component{
+ //教师正在签到
+ constructor(props){
+ super(props);
+
+ this.state={
+ mydatas:[]
+ }
+ }
+
+ componentDidMount() {
+ this.setState({
+ mydatas:this.props.datas
+ })
+
+ }
+
+
+
+
+ componentDidUpdate = (prevProps) => {
+
+
+ }
+ //截止
+ thisEnd=(attendance_id)=>{
+ let thiss=this
+
+ confirm({
+ title: '提示',
+ content: '确认截止此签到吗?',
+ onOk() {
+ const url = `/weapps/attendances/${attendance_id}/end.json`;
+ var data={
+
+ }
+ axios.post(url, data)
+ .then((result) => {
+ if (result.data.status === 0) {
+ // try {
+ // this.props.showNotification(`截止成功`);
+ // }catch (e) {
+ //
+ // }
+ thiss.props.getsetdatas();
+ }else{
+ thiss.props.showNotification(result.data.message);
+
+ }
+ }).catch((error) => {
+ //console.log(error);
+ })
+ },
+ onCancel() {
+
+ },
+ });
+
+ }
+ //删除
+ thisdelete=(attendance_id)=>{
+ let thiss=this
+ confirm({
+ title: '提示',
+ content: '确认删除此签到吗?',
+ onOk () {
+ const url = `/weapps/attendances/${attendance_id}.json`;
+ var data={
+
+ }
+ axios.delete(url, data)
+ .then((result) => {
+ if (result.data.status === 0) {
+ // try {
+ // thiss.props.showNotification(`删除成功`);
+ // }catch (e) {
+ //
+ // }
+
+ thiss.props.getsetdatas();
+ }else{
+ thiss.props.showNotification(result.data.message);
+
+ }
+ }).catch((error) => {
+ //console.log(error);
+ })
+ },
+ onCancel() {
+
+ },
+ });
+
+ }
+
+ //学生签到
+ Signin=(attendance_mode,attendance_id,code)=>{
+
+ const url = `/weapps/course_member_attendances.json`;
+ var data={
+
+ }
+ if(attendance_mode==="QUICK"){
+ //快捷签到
+ data={
+ attendance_mode:"QUICK",
+ attendance_id:attendance_id,
+ }
+ axios.post(url, data)
+ .then((result) => {
+ if (result.data.status === 0) {
+ try {
+ this.props.showNotification(`签到成功`);
+ }catch (e) {
+
+ }
+
+ this.props.getsetdatas();
+ }else{
+ this.props.showNotification(result.data.message);
+
+ }
+ }).catch((error) => {
+ })
+ }else if(attendance_mode==="QRCODE"){
+ //二维码签到
+ data={
+ attendance_mode:"QRCODE",
+ attendance_id:attendance_id,
+ code:code,
+ }
+ this.props.GotomQrcodesodesy(data,true)
+ }else if(attendance_mode==="NUMBER"){
+ //数字签到
+ data={
+ attendance_mode:"NUMBER",
+ attendance_id:attendance_id,
+ code:code,
+ }
+ this.props.Gotomodes(data,true)
+
+ }
+
+
+ }
+
+
+
+ render(){
+ let mydatas=this.props.datas?this.props.datas:[];
+ let Spin= this.props.Spin;
+ return(
+
+
+ {
+ Spin&&Spin===true?
+
+ :
+
+ (
+ mydatas&&mydatas.length>0?
+ mydatas.map((object, index) => {
+ return (
+ this.props.Signinnamestypes(id,b,a)}
+ Signin={(a,b,c)=>this.Signin(a,b,c)}
+ qiandaoxiangq={(b,id)=>this.props.qiandaoxiangq(b,id)}
+ thisdelete={(id)=>this.thisdelete(id)}
+ thisEnd={(id)=>this.thisEnd(id)}
+ item={object} key={index}
+ index={index}
+ defaultActiveKey={this.props.defaultActiveKey}
+ {...this.props}
+ {...this.state}
+ >
+
+ )
+ })
+ :
+
+ )
+
+ }
+
+
+ )
+ }
+}
+export default Teaccomponent;
diff --git a/public/react/src/modules/courses/signin/css/Signinstatistics.css b/public/react/src/modules/courses/signin/css/Signinstatistics.css
new file mode 100644
index 000000000..c7ff88c9f
--- /dev/null
+++ b/public/react/src/modules/courses/signin/css/Signinstatistics.css
@@ -0,0 +1,233 @@
+.gutterrowbox{
+ height:150px;
+ border: none !important;
+}
+.gutterrowbox .ant-card-body{
+ height:150px;
+ position: relative;
+}
+.gutterrowboxcontent{
+ position: absolute;
+ bottom: 20px;
+ font-size:36px;
+ font-weight:400;
+ color:rgba(255,255,255,1);
+}
+.ml14{
+ margin-left: 14px !important;
+}
+.ml8{
+ margin-left: 8px !important;
+}
+.ml20{
+ margin-left: 20px !important;
+}
+.lishiqiandao{
+
+ height: 150px;
+
+ background-size: cover !important;
+ background-position: center !important;
+ background-repeat: no-repeat !important;
+}
+.daokeqiandao{
+
+ height: 150px;
+
+ background-size: cover !important;
+ background-position: center !important;
+ background-repeat: no-repeat !important;
+}
+.kuangkeqiandao{
+
+ height: 150px;
+
+ background-size: cover !important;
+ background-position: center !important;
+ background-repeat: no-repeat !important;
+}
+.qingjiaqiandao{
+
+ height: 150px;
+
+ background-size: cover !important;
+ background-position: center !important;
+ background-repeat: no-repeat !important;
+}
+
+.SigninstatisticsChart{
+ height:519px;
+ background:rgba(255,255,255,1);
+ box-shadow:0px 3px 7px 0px rgba(0, 0, 0, 0.05);
+}
+.pd30{
+ padding:30px;
+}
+.padding03000{
+ padding: 0px 30px 0px 0px;
+}
+
+.mindaoke{
+ width: 20px;
+ height: 20px;
+ background-image: url(./dot-green@2x.png);
+
+ background-size: cover;
+ background-position: center;
+ background-repeat: no-repeat;
+}
+
+.minkuangke{
+ width: 20px;
+ height: 20px;
+ background-image: url(./dot-orange@2x.png);
+
+ background-size: cover;
+ background-position: center;
+ background-repeat: no-repeat;
+}
+
+.minqingjia{
+ width: 20px;
+ height: 20px;
+ background-image: url(./dot-orange@2x1.png);
+
+ background-size: cover;
+ background-position: center;
+ background-repeat: no-repeat;
+}
+
+.Signinstatisticsfont{
+ font-weight: 400;
+ color: rgba(153,153,153,1);
+ text-align: right;
+ margin-right: 20px;
+ line-height: 32px !important;
+ height: 32px !important;
+}
+.Signinstatisticsfontselect .ant-select-selection--single .ant-select-selection__rendered{
+ line-height: 32px !important;
+ height: 32px !important;
+}
+
+#form_in_modal_group_ids .ant-select-selection{
+ background: #fafafa !important;
+}
+
+#form_in_modal_attendance_date .ant-calendar-picker-input {
+ height:40px;
+}
+
+#form_in_modal_start_time{
+ height:40px;
+ background: #fafafa !important;
+}
+
+#form_in_modal_end_time{
+ height:40px;
+ background: #fafafa !important;
+}
+
+.Signedinlistbox .ant-select-selection--single{
+ height:40px !important;
+ background:rgba(255,255,255,1);
+ border:1px solid rgba(234,234,234,1);
+ border-radius:4px;
+}
+
+.Signedinlistbox .ant-select-selection__rendered{
+ line-height: 40px !important;
+}
+
+.Signedintextright{
+ text-align: right;
+}
+
+.color26C7C9{
+ color:#26C7C9;
+}
+
+.colorEAAE4E{
+ color:#EAAE4E;
+}
+
+.colorFF835C{
+ color:#FF835C;
+}
+
+.color909399{
+ color:#909399;
+}
+
+.color1890FF{
+ color:#1890FF;
+}
+
+.backfff .ant-table-thead tr th{
+ background: #fff;
+ border-bottom:1px solid #EBEBEB !important;
+}
+
+.textcenter{
+ text-align: center !important;
+}
+
+.sginboxcolor26C7C9 .ant-select-selection--single{
+ border:1px solid #26C7C9 !important;
+ }
+
+.sginboxcolor26C7C9 .ant-select-arrow{
+ color: #26C7C9 !important;
+}
+
+.sginboxcolorEAAE4E .ant-select-selection--single{
+ border:1px solid #EAAE4E !important;
+}
+
+.sginboxcolorEAAE4E .ant-select-arrow{
+ color: #EAAE4E !important;
+}
+
+.sginboxcolorFF835C .ant-select-selection--single{
+ border:1px solid #FF835C !important;
+}
+
+.sginboxcolorFF835C .ant-select-arrow{
+ color: #FF835C !important;
+}
+
+
+
+.sginboxcolor909399 .ant-select-selection--single{
+ border:1px solid #909399 !important;
+}
+
+.sginboxcolor909399 .ant-select-arrow{
+ color: #909399 !important;
+}
+
+.react-datepicker__time-container .react-datepicker__time .react-datepicker__time-box ul.react-datepicker__time-list li.react-datepicker__time-list-item {
+ height: auto !important;
+ padding: 0px !important;
+ white-space: nowrap !important;
+}
+
+.color26C7C9 .ant-select-selection-selected-value{
+ margin: 0 30% !important;
+}
+
+.colorEAAE4E .ant-select-selection-selected-value{
+ margin: 0 40% !important;
+}
+
+.color909399 .ant-select-selection-selected-value{
+ margin: 0 37% !important;
+}
+
+.colorFF835C .ant-select-selection-selected-value{
+ margin: 0 37% !important;
+}
+
+/*.allSignedinlistbox .ant-select-selection-selected-value{*/
+/* margin: 0 30% !important;*/
+/*}*/
\ No newline at end of file
diff --git a/public/react/src/modules/courses/signin/css/dot-green@2x.png b/public/react/src/modules/courses/signin/css/dot-green@2x.png
new file mode 100644
index 000000000..a9a2cea51
Binary files /dev/null and b/public/react/src/modules/courses/signin/css/dot-green@2x.png differ
diff --git a/public/react/src/modules/courses/signin/css/dot-orange@2x.png b/public/react/src/modules/courses/signin/css/dot-orange@2x.png
new file mode 100644
index 000000000..0489eb573
Binary files /dev/null and b/public/react/src/modules/courses/signin/css/dot-orange@2x.png differ
diff --git a/public/react/src/modules/courses/signin/css/dot-orange@2x1.png b/public/react/src/modules/courses/signin/css/dot-orange@2x1.png
new file mode 100644
index 000000000..a2faaabf7
Binary files /dev/null and b/public/react/src/modules/courses/signin/css/dot-orange@2x1.png differ
diff --git a/public/react/src/modules/courses/signin/css/signincdi.css b/public/react/src/modules/courses/signin/css/signincdi.css
new file mode 100644
index 000000000..7ad9a0d0c
--- /dev/null
+++ b/public/react/src/modules/courses/signin/css/signincdi.css
@@ -0,0 +1,425 @@
+/* 中间居中 */
+.intermediatecenter{
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+}
+/* 简单居中 */
+.intermediatecenterysls{
+ display: flex;
+ align-items: center;
+}
+
+/* 头顶部居中 */
+.topcenter{
+ display: -webkit-flex;
+ flex-direction: column;
+ align-items: center;
+
+}
+/* 均匀分开 */
+.spacearound{
+ display: flex;
+ justify-content: space-around;
+
+}
+/* 两边靠墙中间均匀分开 */
+.spacebetween{
+ display: flex;
+ justify-content: space-between;
+}
+/* 从左分开 */
+.spacearoundflexstart{
+
+ display: flex;
+ justify-content: flex-start;
+}
+.spacebetween{
+ display: flex;
+ justify-content: space-between;
+}
+
+.unpsysls{
+ display: inline-block;
+ text-align: justify;
+ font-size: 28px;
+}
+
+/* x轴正方向排序 */
+/* 一 二 三 四 五 六 七 八 */
+.sortinxdirection{
+ display: flex;
+ flex-direction:row;
+}
+/* x轴反方向排序 */
+/* 八 七 六 五 四 三 二 一 */
+.xaxisreverseorder{
+ display: flex;
+ flex-direction:row-reverse;
+}
+/* 垂直布局 正方向*/
+/* 一
+ 二
+ 三
+ 四
+ 五
+ 六
+ 七
+ 八 */
+.verticallayout{
+ display: flex;
+ flex-direction:column;
+}
+/* 垂直布局 反方向*/
+.reversedirection{
+ display: flex;
+ flex-direction:column-reverse;
+}
+/* 两端对齐 */
+.alignmentatbothends{
+ display: flex;
+ justify-content: space-between;
+}
+.file_path_input{
+ position: absolute;
+ right: -50%;
+}
+.ws100s{
+ width: 100%;
+}
+
+.ws70s{
+ width: 70%;
+ }
+
+.ws75s{
+ width: 75%;
+}
+.ws80s{
+ width: 80%;
+}
+.ws50s{
+ width: 50%;
+}
+.hs30s{
+ height: 30%;
+}
+.ws20s{
+ width: 20%;
+}
+.ws25s{
+ width: 25%;
+}
+.yslmaxheigthk{
+
+}
+.mysligtes{
+ font-size:16px;
+ font-family:Microsoft YaHei;
+ font-weight:bold;
+ color:rgba(144,147,153,1);
+ padding-left: 34px;
+}
+.yslmaxheigthk .ws100s .ant-tabs .ant-tabs-bar {
+ border-bottom: 1px solid #ffffff !important;
+ background: #ffffff !important;
+ background-color: #ffffff !important;
+ margin: 0 !important;
+}
+.yslmaxheigthk .ws100s .ant-tabs .ant-tabs-bar .ant-tabs-nav-container {
+ padding-left: 25px;
+}
+.yslmaxheigthk .ws100s .ant-tabs .ant-tabs-bar .ant-tabs-nav-container .ant-tabs-ink-bar{
+ width: 68px !important;
+ left: 14px;
+
+}
+
+.yslmaxheigthk .ws100s .ant-tabs .ant-tabs-bar .ant-tabs-tab{
+ padding: 25px 16px !important;
+ font-size: 16px;
+ font-family: Microsoft YaHei;
+ font-weight: bold;
+
+}
+.positiondivs{
+ position: absolute;
+ top: 0;
+ right: 0;
+}
+.posiivs{
+ padding: 30px 5px !important;
+ font-size: 16px;
+ font-family: Microsoft YaHei;
+ font-weight: bold;
+ color: #1890ff;
+ margin-right: 20px;
+}
+
+.posiivsicon{
+ padding: 22px 0px !important;
+ font-size: 16px;
+ font-family: Microsoft YaHei;
+ font-weight: bold;
+ color: #1890ff;
+ }
+.posiivsiconmyss{
+ font-size: 14px;
+ font-family: Microsoft YaHei;
+ color: #999999;
+}
+.xiaoshou{
+ cursor:pointer !important;
+}
+.xiaoshout{
+ cursor:default !important;
+}
+
+.teacherentrydiv{
+ padding-left: 32px;
+ padding-right: 32px;
+ padding-top: 20px;
+ padding-bottom: 20px;
+}
+.teacherentrydivs{
+ padding-left: 25px;
+ padding-right: 25px;
+ padding-top: 20px;
+ padding-bottom: 20px;
+}
+.teachedivp{
+ font-size:16px;
+ font-family:Microsoft YaHei;
+ font-weight:bold;
+ color:rgba(51,51,51,1);
+}
+.ymaxnamewidthdivp{
+ max-width:100%;
+ width: 100%;
+ overflow:hidden;
+ text-overflow:ellipsis;
+ white-space:nowrap;
+ cursor: default;
+}
+.teachedivps{
+ font-size:14px;
+ font-family:Microsoft YaHei;
+ font-weight:400;
+ color:rgba(144,147,153,1);
+}
+.teachedivpsy{
+ font-size:14px;
+ font-family:Microsoft YaHei;
+ font-weight:400;
+ color:#333333;
+
+}
+.progressivps{
+ width:200px;
+ margin-left: 10px;
+
+}
+.progressivpss{
+ font-size:12px;
+ line-height: 23px;
+ font-family:Microsoft YaHei;
+ font-weight:400;
+ color:rgba(64,158,255,1);
+ margin-left: 15px;
+}
+.w60ys{
+ width: 60px;
+ }
+
+.ymaxnamewidth60{
+ max-width: 70px;
+ width: 70px;
+ overflow:hidden;
+ text-overflow:ellipsis;
+ white-space:nowrap;
+ cursor: default;
+}
+.ymaxnamewidth80{
+ max-width: 80px;
+ width: 80px;
+ overflow:hidden;
+ text-overflow:ellipsis;
+ white-space:nowrap;
+ cursor: default;
+}
+.w80ys{
+ width: 80px;
+}
+
+.jiezhis{
+ font-size:14px;
+ font-family:Microsoft YaHei;
+ font-weight:400;
+ color:rgba(64,158,255,1);
+}
+.shanchu{
+ font-size:14px;
+ font-family:Microsoft YaHei;
+ font-weight:400;
+ color:rgba(245,108,108,1);
+ margin-right: 30px;
+}
+
+.qiandaobutton{
+ font-size:16px;
+ font-family:Microsoft YaHei;
+ font-weight:400;
+ color:rgba(255,255,255,1);
+ text-align: center;
+ line-height: 40px;
+ width:100px;
+ height:40px;
+ background:rgba(64,158,255,1);
+ border-radius:4px;
+}
+
+.zcqiandao{
+ width:100px;
+ height:40px;
+ border:1px solid rgba(38,199,201,1);
+ border-radius:4px;
+ font-size:16px;
+ font-family:Microsoft YaHei;
+ font-weight:400;
+ color:rgba(38,199,201,1);
+ text-align: center;
+ line-height: 40px;
+
+}
+.qjqiandao{
+ width:100px;
+ height:40px;
+ border:1px solid #EAAE4E;
+ border-radius:4px;
+ font-size:16px;
+ font-family:Microsoft YaHei;
+ font-weight:400;
+ color:#EAAE4E;
+ text-align: center;
+ line-height: 40px;
+
+
+}
+
+.kkqiandao{
+ width:100px;
+ height:40px;
+ border:1px solid #FF835C;
+ border-radius:4px;
+ font-size:16px;
+ font-family:Microsoft YaHei;
+ font-weight:400;
+ color:#FF835C;
+ text-align: center;
+ line-height: 40px;
+
+}
+.h40s{
+ line-height: 40px !important;
+}
+.h28s{
+ line-height: 28px !important;
+}
+.mt40{
+ margin-top: 40px !important;
+}
+
+.h500{
+ min-height: 500px;
+}
+.kkp{
+ font-size:14px;
+ font-family:Microsoft YaHei;
+ font-weight:400;
+}
+.pr32{
+ padding-right: 32px;
+}
+
+.mr20r{
+ margin-right: 20px;
+}
+
+.color-reds{
+ color:rgba(245,108,108,1) !important;
+}
+
+.fh{
+ font-size:16px;
+ font-family:Microsoft YaHei;
+ font-weight:400;
+ color:rgba(153,153,153,1);
+
+}
+
+.colorbluesigin{
+ font-size:16px;
+ font-weight:bold;
+ color:rgba(51,51,51,1);
+}
+.sptits{
+ font-size:20px;
+ font-family:MicrosoftYaHeiSemibold;
+ color:rgba(51,51,51,1);
+}
+.sptitss{
+ font-size:14px;
+ font-family:MicrosoftYaHei;
+ color:rgba(136,136,136,1);
+ line-height:40px;
+}
+.tbrt{
+ padding-top: 22px;
+ padding-left: 28px;
+}
+.tbrt .ts {
+ font-size:12px;
+ font-family:MicrosoftYaHei;
+ color:rgba(255,255,255,1);
+}
+
+.tbrt .tss{
+ font-size:30px;
+ font-family:MicrosoftYaHei-Bold,MicrosoftYaHei;
+ font-weight:bold;
+ color:rgba(255,255,255,1);
+ line-height: 33px;
+}
+.maxnamewidth150s{
+ width: 150px;
+ max-width: 150px;
+ overflow:hidden;
+ text-overflow:ellipsis;
+ white-space:nowrap;
+ cursor: default;
+}
+.maxnamewidth200s{
+ text-align: center;
+ width: 200px;
+ max-width:200px;
+ overflow:hidden;
+ text-overflow:ellipsis;
+ white-space:nowrap;
+ cursor: default;
+}
+.maxnamewidth100s{
+ width: 100px;
+ max-width: 100px;
+ overflow:hidden;
+ text-overflow:ellipsis;
+ white-space:nowrap;
+ cursor: default;
+}
+
+.font-14{
+ font-size: 14px !important;
+}
+.mr32{
+ margin-right: 32px;
+}
diff --git a/public/react/src/modules/courses/signin/model/Createsignmodel.js b/public/react/src/modules/courses/signin/model/Createsignmodel.js
new file mode 100644
index 000000000..117531750
--- /dev/null
+++ b/public/react/src/modules/courses/signin/model/Createsignmodel.js
@@ -0,0 +1,358 @@
+import "../css/Signinstatistics.css"
+import React from 'react'
+import { Modal , Form, Input, Radio,DatePicker,Select,Button} from 'antd';
+import moment from 'moment';
+import axios from 'axios';
+import TimePicker from "react-datepicker";
+import "react-datepicker/dist/react-datepicker.css";
+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(0,60)
+ }
+}
+
+function disabledDate(current) {
+ return current && current < moment().endOf('day').subtract(1, 'days');
+}
+
+const CollectionCreateForm = Form.create({ name: 'form_in_modal' })(
+
+ class extends React.Component {
+ constructor(props){
+ super(props);
+ this.state = {
+ course_groups:[],
+ type:false,
+ dateString:null,
+ start_time: "",
+ end_time:""
+ }
+ }
+
+
+ handleChangestart_time = (date) => {
+
+ this.setState({
+ start_time: date
+ });
+ };
+
+ handleChangeend_time=(date)=>{
+
+ this.setState({
+ end_time: date
+ });
+ }
+ componentDidMount() {
+ const coursesId=this.props.match.params.coursesId;
+ let newurl=`/courses/${coursesId}/all_course_groups.json`;
+ axios.get(newurl).then((response) => {
+
+ this.setState({
+ course_groups:response.data.course_groups
+ })
+
+ })
+
+ }
+
+ hideCreatesign=(e)=>{
+ e.preventDefault();
+ const {settabsdata,hideCreatesign} = this.props;
+ const coursesId=this.props.match.params.coursesId;
+ this.setState({
+ type:true
+ })
+ this.props.form.validateFields((err, values) => {
+ if (!err) {
+ if(moment(values.end_time).format('HH:mm') {
+ if (response.data.status == 0) {
+ this.props.showNotification(`创建签到成功`);
+ this.setState({
+ type:false
+ })
+ hideCreatesign()
+ settabsdata()
+ }
+ })
+ .catch(function (error) {
+ console.log(error);
+ });
+ }else{
+ this.setState({
+ type:false
+ })
+ }
+
+
+ });
+ }
+ // getDisabledHours=()=> {
+ // let hours = []
+ // if(this.state.dateString===moment().format('YYYY-MM-DD')){
+ // let time = moment().format('HH:mm')
+ // let timeArr = time.split(':')
+ // for (var i = 0; i < parseInt(timeArr[0]); i++) {
+ // hours.push(i)
+ // }
+ // }
+ //
+ // return hours
+ // }
+ //
+ // getDisabledMinutes=(selectedHour)=>{
+ // let minutes = []
+ // if(this.state.dateString===moment().format('YYYY-MM-DD')){
+ // let time = moment().format('HH:mm')
+ // let timeArr = time.split(':')
+ // if (selectedHour == parseInt(timeArr[0])) {
+ // for(var i = 0; i < parseInt(timeArr[1]); i++) {
+ // minutes.push(i)
+ // }
+ // }
+ // }
+ // return minutes
+ // }
+
+ onChange=(date, dateString)=>{
+ this.setState({
+ dateString:dateString
+ })
+ }
+ render() {
+ const { visible, form ,setRadio,Radiolist,hideCreatesign} = this.props;
+ let {course_groups}=this.state;
+ const { getFieldDecorator } = form;
+ const { Option } = Select;
+ const formItemLayout = {
+ labelCol: { span: 4 },
+ wrapperCol: { span: 19},
+ };
+
+ const leftbuton={
+ "width":"130px",
+ "height":"40px",
+ "border":"1px solid rgba(76,172,255,1)",
+ "borderRadius":"4px",
+ }
+
+ const rightbuton={
+ "width":"130px",
+ "height":"40px",
+ "background":"#4CACFF",
+ "borderRadius":"4px",
+ }
+ const format = 'HH:mm';
+
+ return (
+
+
+ {getFieldDecorator('name', {
+ rules: [{ required: true, message: '请输入签到名称' },{whitespace:true,message: '请勿输入空格'}],
+ })()}
+
+
+
+ {getFieldDecorator('group_ids')(
+ ,
+ )}
+
+
+
+ {getFieldDecorator('mode', {
+ rules: [{ required: true, message: '请选择签到方式' }],
+ })(
+ trigger.parentNode}>
+ 快捷签到
+ 签到码签到
+ 二维码签到
+ ,
+ )}
+ {Radiolist==="QUICK"?学生点击签到按钮即可完成签到
:""}
+
+ {Radiolist==="NUMBER"?学生需要输入签到码才能完成签到
:""}
+
+ {Radiolist==="QRCODE"?学生需从小程序进入课堂扫码才能完成签到
:""}
+
+
+
+ {getFieldDecorator('attendance_date', {
+ rules: [{ type: 'object', required: true, message: '请选择签到日期',}],
+ })( trigger.parentNode}
+ disabledTime={disabledDateTime}
+ disabledDate={disabledDate}
+ onChange={this.onChange}
+ />)}
+
+
+
+ {getFieldDecorator('start_time', {
+ rules: [{ type: 'object', required: true, message: '请选择开始时间' }],
+ })(
+ // trigger.parentNode}/>
+ this.handleChangestart_time(date)}
+ showTimeSelect
+ showTimeSelectOnly
+ timeIntervals={10}
+ timeCaption="Time"
+ timeFormat="HH:mm"
+ dateFormat="HH:mm"
+ getPopupContainer={trigger => trigger.parentNode}
+ />
+ )}
+
+
+
+ {getFieldDecorator('end_time', {
+ rules: [{ type: 'object', required: true, message: '请选择结束时间' }],
+ })(
+ // trigger.parentNode}
+ // disabledHours={this.getDisabledHours}
+ // disabledMinutes={this.getDisabledMinutes}
+ //
+ // />
+ this.handleChangeend_time(date)}
+ showTimeSelect
+ showTimeSelectOnly
+ timeIntervals={10}
+ minTime={this.state.dateString===moment().format('YYYY-MM-DD')||this.state.dateString===null?new Date():false}
+ maxTime={this.state.dateString===moment().format('YYYY-MM-DD')||this.state.dateString===null?moment().endOf('day').toDate():false}
+ timeCaption="Time"
+ timeFormat="HH:mm"
+ dateFormat="HH:mm"
+ getPopupContainer={trigger => trigger.parentNode}
+ />
+ )}
+
+
+
+
+
+
+
+
+ );
+ }
+ },
+);
+
+class Createsignmodel extends React.Component {
+ state = {
+ Radiolist: "",
+ };
+ setRadio=(e)=>{
+
+ this.setState({
+ Radiolist:e.target.value
+ })
+ }
+ render() {
+ return (
+
+ this.setRadio(e)}
+ />
+
+ );
+ }
+}
+
+export default Createsignmodel;
+
+
diff --git a/public/react/src/modules/courses/signin/model/Qrcodesignin.js b/public/react/src/modules/courses/signin/model/Qrcodesignin.js
new file mode 100644
index 000000000..6bc517043
--- /dev/null
+++ b/public/react/src/modules/courses/signin/model/Qrcodesignin.js
@@ -0,0 +1,77 @@
+import React,{ Component } from "react";
+import { Modal , Button} from 'antd';
+import QRCode from 'qrcode.react';
+
+class Qrcodesignin extends Component {
+ constructor(props) {
+ super(props)
+ }
+ render() {
+
+ const leftbuton={
+ "width":"130px",
+ "height":"40px",
+ "border":"1px solid rgba(76,172,255,1)",
+ "borderRadius":"4px",
+ }
+
+ const rightbuton={
+ "width":"130px",
+ "height":"40px",
+ "background":"#4CACFF",
+ "borderRadius":"4px",
+ }
+ return(
+
+ {this.props.Qrcodesignintype?
+
+
+ :""}
+
+
+ )
+ }
+
+}
+
+
+
+
+
+
+export default Qrcodesignin
diff --git a/public/react/src/modules/courses/signin/model/Signinname.js b/public/react/src/modules/courses/signin/model/Signinname.js
new file mode 100644
index 000000000..0e88e3287
--- /dev/null
+++ b/public/react/src/modules/courses/signin/model/Signinname.js
@@ -0,0 +1,105 @@
+import React,{ Component } from "react";
+
+import { Modal , Form, Input,Button} from 'antd';
+import axios from 'axios';
+
+class Signinname extends Component {
+ constructor(props) {
+ super(props)
+ }
+ setdatas=()=>{
+ this.props.form.validateFields((err, values) => {
+ if (!err) {
+ const url = `/weapps/attendances/${this.props.switattendance_id}.json`;
+ let data={
+ name:values.name,
+ }
+ axios.put(url, data)
+ .then((result) => {
+ if (result.data.status === 0) {
+ try {
+ this.props.showNotification(`修改成功`);
+ }catch (e) {
+
+ }
+ this.props.getsetdatas();
+ this.props.Signinnamestypes(null,false,"")
+ }else{
+ this.props.showNotification(result.data.message);
+
+ }
+ }).catch((error) => {
+ })
+ }
+ });
+
+
+
+ }
+ render() {
+ const { getFieldDecorator } = this.props.form;
+ const formItemLayout = {
+ wrapperCol: { span: 25},
+ };
+
+ const leftbuton={
+ "width":"130px",
+ "height":"40px",
+ "border":"1px solid rgba(76,172,255,1)",
+ "borderRadius":"4px",
+ }
+
+ const rightbuton={
+ "width":"130px",
+ "height":"40px",
+ "background":"#4CACFF",
+ "borderRadius":"4px",
+ }
+ return(
+
+ {this.props.Signinnamestype?
+
+
+ {getFieldDecorator('name', {initialValue: this.props.mybianjiname,
+ rules: [{ required: true, message: '请输入签到名称' }],
+ })()}
+
+
+
+
+
+
+ :""}
+
+
+ )
+ }
+
+}
+
+
+
+
+const Signinnames = Form.create({ name: 'Signinnames' })(Signinname);
+
+export default Signinnames
diff --git a/public/react/src/modules/courses/signin/model/Studentssignmodel.js b/public/react/src/modules/courses/signin/model/Studentssignmodel.js
new file mode 100644
index 000000000..0bb736c3e
--- /dev/null
+++ b/public/react/src/modules/courses/signin/model/Studentssignmodel.js
@@ -0,0 +1,107 @@
+import React,{ Component } from "react";
+
+import { Modal , Form, Input,Button} from 'antd';
+import axios from 'axios';
+
+class Studentssignmodel extends Component {
+ constructor(props) {
+ super(props)
+ }
+ setdatas=()=>{
+ this.props.form.validateFields((err, values) => {
+ if (!err) {
+ const url = `/weapps/course_member_attendances.json`;
+ let data={
+ code:values.name,
+ attendance_mode:"NUMBER",
+ attendance_id:this.props.Studentssigntypedata.attendance_id,
+ }
+ axios.post(url, data)
+ .then((result) => {
+ if (result.data.status === 0) {
+ try {
+ this.props.showNotification(`签到成功`);
+ }catch (e) {
+
+ }
+ this.props.getsetdatas();
+ this.props.Gotomodes(null,false)
+ }else{
+ this.props.showNotification(result.data.message);
+
+ }
+ }).catch((error) => {
+ })
+ }
+ });
+
+
+
+ }
+ render() {
+ const { getFieldDecorator } = this.props.form;
+ const formItemLayout = {
+ wrapperCol: { span: 25},
+ };
+
+ const leftbuton={
+ "width":"130px",
+ "height":"40px",
+ "border":"1px solid rgba(76,172,255,1)",
+ "borderRadius":"4px",
+ }
+
+ const rightbuton={
+ "width":"130px",
+ "height":"40px",
+ "background":"#4CACFF",
+ "borderRadius":"4px",
+ }
+ return(
+
+ {this.props.Studentssigntype?
+
+
+ {getFieldDecorator('name', {
+ rules: [{ required: true, message: '请输入签到码' }],
+ })()}
+
+
+
+
+
+
+ :""}
+
+
+ )
+ }
+
+}
+
+
+
+
+const Studentssignmodels = Form.create({ name: 'Studentssignmodel' })(Studentssignmodel);
+
+export default Studentssignmodels
diff --git a/public/react/src/modules/courses/signin/model/sigininmodes.js b/public/react/src/modules/courses/signin/model/sigininmodes.js
new file mode 100644
index 000000000..e69de29bb
diff --git a/public/react/src/modules/courses/signin/mymain/Signinmain.js b/public/react/src/modules/courses/signin/mymain/Signinmain.js
new file mode 100644
index 000000000..6912508ba
--- /dev/null
+++ b/public/react/src/modules/courses/signin/mymain/Signinmain.js
@@ -0,0 +1,44 @@
+import React,{ Component } from "react";
+import '../css/signincdi.css';
+import { Tabs } from 'antd';
+import Teachers_signin from '../teacher/Teachers_signin';
+import Students_signin from '../student/Signindetails';
+import axios from 'axios';
+
+const { TabPane } = Tabs;
+// 主签到目录 主签到目录
+class Signinmain extends Component{
+ constructor(props){
+ super(props);
+
+ this.state={
+
+ }
+ }
+
+ componentDidMount() {
+
+ }
+
+ componentDidUpdate = (prevProps) => {
+
+
+ }
+
+
+ // 主签到目录
+ render(){
+ const isAdmin = this.props.isAdmin()
+
+ return(
+
+
+
+
+
+
+
+ )
+ }
+}
+export default Signinmain;
diff --git a/public/react/src/modules/courses/signin/student/Signedinlist.js b/public/react/src/modules/courses/signin/student/Signedinlist.js
new file mode 100644
index 000000000..ea5ffb998
--- /dev/null
+++ b/public/react/src/modules/courses/signin/student/Signedinlist.js
@@ -0,0 +1,395 @@
+import "../css/Signinstatistics.css"
+import React,{ Component } from "react";
+import { Row, Col,Select,Table,Pagination } from 'antd';
+import axios from 'axios';
+import LoadingSpin from "../../../../common/LoadingSpin";
+import NoneDatas from "../component/NoneDatas";
+const { Option } = Select;
+
+class Signedinlist extends Component {
+
+ constructor(props) {
+ super(props)
+ this.state={
+ limit:5,
+ page:1,
+ loading:false,
+ attendanceslist:[],
+ data:null,
+ group_ids:[],
+ members_count:0,
+ attendance_status:undefined,
+ state:[
+ {id:undefined,name:"全部状态"},
+ {id:"NORMAL",name:"正常签到"},
+ {id:"LEAVE",name:"请 假"},
+ {id:"ABSENCE",name:this.props.defaultActiveKey ==="2"?"旷 课":"未签到"},
+ ],
+ newstate:[
+ {id:"NORMAL",name:"正常签到"},
+ {id:"LEAVE",name:"请 假"},
+ {id:"ABSENCE",name:this.props.defaultActiveKey ==="2"?"旷 课":"未签到"},
+ ],
+ course_members_count:'--',
+ attendance_count:'--',
+ }
+ }
+
+ componentDidMount() {
+ this.getdatas(this.props&&this.props.switattendance_id,1,[],undefined)
+ // this.getpath()
+ }
+ componentDidUpdate(prevProps, prevState) {
+ if(prevProps.headdata!=this.props.headdata){
+
+ if(this.props.headdata){
+ let listattendanceslist=[];
+ listattendanceslist.push({id:undefined,name:"全部分班"})
+ if(this.props.headdata.course_groups){
+
+ if(this.props.headdata.course_groups.length>0){
+ this.props.headdata.course_groups.map((item,key)=>{
+ listattendanceslist.push(item)
+ })
+ }
+ }
+ this.setState({
+ attendanceslist:listattendanceslist,
+ data:this.props.headdata,
+ course_members_count:this.props.headdata.normal_count,
+ attendance_count:this.props.headdata.all_count
+ })
+ }
+
+
+ }
+ }
+ getdatas=(id,page,group_ids,attendance_status)=>{
+ this.setState({
+ loading:true,
+ member_attendances:[],
+ })
+ let that=this;
+ let url=`/weapps/course_member_attendances.json`;
+ axios.get(url,{params:{
+ group_ids:group_ids,
+ attendance_id:id,
+ attendance_status:attendance_status,
+ page:page,
+ limit:5,
+ }
+ }).then((response) => {
+
+ if(response){
+ this.setState({
+ member_attendances:response.data.member_attendances,
+ members_count:response.data.members_count,
+
+ })
+
+ }
+ this.setState({
+ loading:false
+ })
+ }).catch((error) => {
+ that.setState({
+ loading:false
+ })
+
+ });
+ }
+ handleChangegroup_ids=(value)=>{
+ let neval
+ if(!value){
+ neval=[]
+ this.setState({
+ group_ids: [],
+ page:1
+ })
+ }else{
+ neval=[value]
+ this.setState({
+ group_ids: [value],
+ page:1
+ })
+ }
+
+ let {page,attendance_status}=this.state;
+ this.getdatas(this.props&&this.props.switattendance_id,1,neval,attendance_status)
+ if(this.props.defaultActiveKey==="1"){
+ this.getpath(value)
+ }
+
+ }
+ getpath=(id)=>{
+ let listattendanceslist=[]
+ let url=`/weapps/attendances/${this.props&&this.props.switattendance_id}.json`;
+ axios.get(url).then((response) => {
+ if(response.data){
+ listattendanceslist.push({id:undefined,name:"全部分班"})
+ if(response.data.course_groups.length>0){
+ response.data.course_groups.map((item,key)=>{
+ listattendanceslist.push(item)
+ })
+ }
+ if(id){
+ response.data.course_groups.map((item,key)=>{
+ if(item.id===id){
+ this.setState({
+ course_members_count:item.course_members_count,
+ attendance_count: item.attendance_count
+ })
+ }
+
+ })
+ }else{
+ this.setState({
+ course_members_count:response.data.normal_count,
+ attendance_count: response.data.all_count
+ })
+ }
+ this.setState({
+ attendanceslist:listattendanceslist,
+ data:response.data
+ })
+
+ }
+
+ })
+ }
+ handleChangestate=(value)=>{
+ let neval
+ if(!value){
+ neval=undefined
+ this.setState({
+ attendance_status:undefined,
+ page:1
+ })
+ }else{
+ neval=value
+ this.setState({
+ attendance_status: value,
+ page:1
+ })
+ }
+
+ let {page,group_ids}=this.state;
+ this.getdatas(this.props&&this.props.switattendance_id,1,group_ids,neval)
+ }
+ paginationonChange = (pageNumber) => {
+ this.setState({
+ page: pageNumber,
+ })
+ let {group_ids,attendance_status}=this.state;
+ this.getdatas(this.props&&this.props.switattendance_id,pageNumber,group_ids,attendance_status)
+
+ }
+
+ handleChange=(attendance_status,value)=>{
+
+ let {member_attendances}=this.state;
+ let newmember_attendances=member_attendances;
+
+ newmember_attendances.map((item,key)=>{
+ if(item.user_id===value){
+ item.attendance_status=attendance_status
+ }
+ })
+
+
+ let url=`/weapps/course_member_attendances/update_status.json`;
+
+ axios.post(url, {
+ attendance_id:this.props.switattendance_id,
+ attendance_status:attendance_status,
+ course_id:this.props.match.params.coursesId,
+ user_id: value,
+ })
+ .then((response) => {
+ if (response.data.status == 0) {
+ this.props.showNotification(`修改状态成功`);
+ this.setState({
+ member_attendances:newmember_attendances
+ })
+ this.props.mygetdatas()
+ }
+ })
+ .catch(function (error) {
+ console.log(error);
+ });
+
+
+
+ }
+ render() {
+ let {attendanceslist,state,data,member_attendances,newstate,attendance_status}=this.state;
+
+ const columns = [
+ {
+ title: '序号',
+ dataIndex: 'index',
+ key: 'index',
+ width:300,
+ className: "textcenter",
+ },
+ {
+ title: '姓名',
+ dataIndex: 'user_name',
+ key: 'user_name',
+ width:300,
+ className: "textcenter",
+ render: (text, record) => (
+ {record.user_name===null?"--":record.user_name}
+ )
+ },
+ {
+ title: '学号',
+ dataIndex: 'student_id',
+ key: 'student_id',
+ width:300,
+ className: "textcenter",
+ render: (text, record) => (
+ {record.student_id===null?"--":record.student_id}
+ )
+ },
+ {
+ title: '状态',
+ key: 'attendance_status',
+ width:300,
+ dataIndex: 'attendance_status',
+ className: "textcenter",
+ render: (text, record) => (
+
+
+
+
+ ),
+ },
+ ];
+
+ return(
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {this.props.defaultActiveKey==="2"?
+ 正常签到:{data&&data.normal_count}
+ 请假:{data&&data.leave_count}
+ 旷课:{data&&data.absence_count}
+ :
+ 已签到:{this.state.course_members_count}
+ 应签到:{this.state.attendance_count}
+ }
+
+
+
+
+
+
+
+ {
+ this.state.loading===true?
+
+
+
+ :
+ member_attendances&&member_attendances.length===0?
+
+ {/**/}
+
+
+
+ :
+ // loading={this.state.loading}
+
+
+ }
+
+
+
+
+ {
+ member_attendances&&member_attendances.length>0?
+
+ :""
+ }
+
+
+
+
+ )
+ }
+
+}
+
+
+export default Signedinlist
diff --git a/public/react/src/modules/courses/signin/student/Signindetails.js b/public/react/src/modules/courses/signin/student/Signindetails.js
new file mode 100644
index 000000000..a5df6c2b2
--- /dev/null
+++ b/public/react/src/modules/courses/signin/student/Signindetails.js
@@ -0,0 +1,77 @@
+import React,{ Component } from "react";
+import '../css/signincdi.css';
+import Detailss from '../component/Detailss';
+import Signedinlist from './Signedinlist'
+import axios from 'axios';
+
+//在线学习
+class Signindetails extends Component{
+ constructor(props){
+ super(props);
+
+ this.state={
+ headdata:null
+ }
+
+ }
+
+ componentDidMount() {
+ this.mygetdatas()
+ }
+ mygetdatas=()=>{
+ const switattendance_id=this.props.switattendance_id;
+ let urls = `/weapps/attendances/${switattendance_id}.json`;
+ axios.get(urls).then((response) => {
+ //.log(response);
+ if(response){
+ if(response.data){
+ this.setState({
+ headdata:response.data
+ })
+
+ }
+ }
+ })
+ }
+
+
+
+ render(){
+ let {headdata}= this.state;
+ return(
+
+
+
+
+ this.props.qiandaoxiangq(false)}>
+
this.props.qiandaoxiangq(false)}>正在签到
+
+
+
+
+
+
+ {/* 列表+筛选 */}
+
+ this.mygetdatas()}
+ defaultActiveKey={this.props.defaultActiveKey}
+ switattendance_id={this.props.switattendance_id}
+ headdata={headdata}
+ {...this.props}
+ {...this.state}
+ />
+
+
+
+ )
+ }
+}
+export default Signindetails;
diff --git a/public/react/src/modules/courses/signin/teacher/Teachers_signin.js b/public/react/src/modules/courses/signin/teacher/Teachers_signin.js
new file mode 100644
index 000000000..bda49fa6a
--- /dev/null
+++ b/public/react/src/modules/courses/signin/teacher/Teachers_signin.js
@@ -0,0 +1,394 @@
+import React,{ Component } from "react";
+import '../css/signincdi.css';
+import { Tabs,Pagination} from 'antd';
+import {queryString} from 'educoder';
+import Teaccomponent from '../component/teachercomponent/Teaccomponent';
+import Createsignmodel from '../model/Createsignmodel';
+import Studentssignmodels from "../model/Studentssignmodel";
+import Qrcodesignin from "../model/Qrcodesignin";
+import Signinname from '../model/Signinname';
+import Signinstatistics from "../Signinstatistics/Signinstatistics";
+import Signindetails from '../student/Signindetails';
+
+import axios from 'axios';
+
+const { TabPane } = Tabs;
+//在线学习
+
+class Students_signin extends Component{
+ constructor(props){
+ super(props);
+
+ this.state={
+ visible:false,
+ page:1,
+ limit:5,
+ count:50,
+ defaultActiveKey:"1",
+ attendances_count:0,
+ datas:[],
+ normal_count:0,
+ leave_count:0,
+ absence_count:0,
+ Studentssigntype:false,
+ Studentssigntypedata:null,
+ Qrcodesignintype:false,
+ Qrcodesignintypedata:null,
+ switchs:false,
+ switattendance_id:null,
+ Spin:false,
+ Signinnamestype:false,
+ mybianjiname:"",
+
+ }
+ }
+
+ componentDidMount() {
+ let data={
+ key:"1",
+ page:1,
+ limit:5
+ }
+ this.gogetdatas(data);
+
+ // const query = this.props.location.search;
+ // const parsed = queryString.parse(query);
+ // console.log("parsed");
+ // console.log(parsed);
+ }
+
+ componentDidUpdate = (prevProps) => {
+
+
+ }
+
+ callback=(key)=> {
+ //.log(key);
+ this.setState({
+ defaultActiveKey: key,
+ page:1,
+ limit:5
+ })
+ let data={
+ key:key,
+ page:1,
+ limit:5
+ }
+ if(key==="1" || key ==="2"){
+ this.gogetdatas(data);
+ }
+ }
+
+ gogetdatas =(mydata)=>{
+ this.setState({
+ Spin:true
+ })
+ const coureid=this.props.match.params.coursesId;
+ let urls = `/courses/${coureid}/attendances.json`;
+ let arry={}
+ if(mydata.key==="1" || mydata.key ===1){
+ arry={
+ page:mydata.page,
+ limit:mydata.limit,
+ };
+ }else if(mydata.key==="2" || mydata.key ===2){
+ arry={
+ history:true,
+ page:mydata.page,
+ limit:mydata.limit,
+ }
+ }
+ axios.get(urls, {
+ params: arry
+ }).then((response) => {
+ //.log(response);
+ if(response){
+ if(response.data){
+ this.setState({
+ attendances_count:response.data.attendances_count,
+ datas:response.data.attendances,
+ normal_count:response.data.normal_count,
+ leave_count:response.data.leave_count,
+ absence_count:response.data.absence_count,
+ })
+ if(response.data.attendances.length===0&&mydata.page!==1){
+ this.setState({
+ page:mydata.page-1,
+ limit:5
+ })
+ let data={
+ key: mydata.key,
+ page:mydata.page-1,
+ limit:5
+ }
+ this.gogetdatas(data);
+ }
+ }
+ }
+ this.setState({
+ Spin:false
+ })
+ }).catch((error) => {
+ this.setState({
+ Spin:false
+ })
+ })
+ }
+
+ Createsign=()=>{
+ this.setState({
+ visible:true
+ })
+ }
+
+
+ hideCreatesign=()=>{
+ this.setState({
+ visible:false
+ })
+ }
+
+
+ paginationonChange = (pageNumber) => {
+ this.setState({
+ page: pageNumber,
+ })
+
+ let data={
+ key:this.state.defaultActiveKey,
+ page:pageNumber,
+ limit:5
+ }
+ this.gogetdatas(data);
+
+ }
+
+ getsetdatas=()=>{
+ let data={
+ key:this.state.defaultActiveKey,
+ page:this.state.page,
+ limit:5
+ }
+ this.gogetdatas(data);
+ }
+
+ Gotomodes(data,bool){
+ if(bool===true){
+ this.setState({
+ Studentssigntypedata:data,
+ Studentssigntype:true
+ })
+ }else{
+ this.setState({
+ Studentssigntype:false,
+ Studentssigntypedata:null,
+
+ })
+ }
+
+
+ }
+ GotomQrcodesodesy(data,bool){
+ if(bool===true){
+ this.setState({
+ Qrcodesignintype:true,
+ Qrcodesignintypedata:data,
+ })
+ }else{
+ this.setState({
+ Qrcodesignintype:false,
+ Qrcodesignintypedata:null,
+
+ })
+ }
+
+
+ }
+
+ qiandaoxiangq=(bool,id)=>{
+ this.setState({
+ switchs:bool,
+ switattendance_id:id,
+ })
+ if(bool===false){
+ this.getsetdatas();
+ }
+ }
+
+
+ settabsdata=()=>{
+ let data={
+ defaultActiveKey:"1",
+ key:"1",
+ page:1,
+ limit:5
+ }
+ this.gogetdatas(data);
+ }
+
+ Signinnamestypes=(id,bool,name)=>{
+ this.setState({
+ switattendance_id:id,
+ Signinnamestype:bool,
+ mybianjiname:name,
+ })
+ }
+
+
+ render(){
+
+ let {page,per_page,count,defaultActiveKey,limit,attendances_count,datas,absence_count,leave_count,normal_count,
+ Studentssigntype,Studentssigntypedata,Qrcodesignintype,Qrcodesignintypedata,switchs,switattendance_id,Spin,
+ mybianjiname
+ } =this.state;
+ const isAdmin =this.props.isAdmin();
+
+ return(
+
+
+
+ {/*编辑名称*/}
+
this.Signinnamestypes(id,b,a)}
+ getsetdatas={()=>this.getsetdatas()}
+ />
+ {/*创建实训*/}
+ {this.state.visible===true?this.hideCreatesign()}
+ settabsdata={()=>this.settabsdata()}
+ />:""}
+ {/*签到*/}
+ this.Gotomodes(d,b)}
+ getsetdatas={()=>this.getsetdatas()}
+ />
+ {/*二维码*/}
+ this.getsetdatas()}
+ GotomQrcodesodesy={(d,b)=>this.GotomQrcodesodesy(d,b)}
+ />
+ {
+ switchs===false?
+
+
+
+
+ 共{attendances_count}个签到正在进行
+ this.Signinnamestypes(id,b,a)}
+ qiandaoxiangq={(b,id)=>this.qiandaoxiangq(b,id)}
+ Gotomodes={(d,b)=>this.Gotomodes(d,b)}
+ GotomQrcodesodesy={(d,b)=>this.GotomQrcodesodesy(d,b)}
+ getsetdatas={()=>this.getsetdatas()}
+ datas={datas}
+ defaultActiveKey={defaultActiveKey}
+ {...this.state}
+ {...this.props}
+
+ >
+
+
+
+
+ {attendances_count>0?
:''}
+
+
+
+
+
已完成{attendances_count}次签到
+ {
+ isAdmin===false?
+
+
旷课:{absence_count}
+
请假:{leave_count}
+
正常签到:{normal_count}
+
+
+ :
+ ""
+ }
+
+
+
+
+ this.Signinnamestypes(id,b,a)}
+ qiandaoxiangq={(b,id)=>this.qiandaoxiangq(b,id)}
+ Gotomodes={(d,b)=>this.Gotomodes(d,b)}
+ GotomQrcodesodesy={(d,b)=>this.GotomQrcodesodesy(d,b)}
+ getsetdatas={()=>this.getsetdatas()}
+ datas={datas}
+ defaultActiveKey={defaultActiveKey}
+ {...this.state}
+ {...this.props}
+ >
+
+
+
+ {attendances_count>0?
:''
+ }
+
+ {
+ isAdmin===true?
+
+ {defaultActiveKey&&defaultActiveKey==="3"?:""}
+
+ :
+ ""
+ }
+
+
+ {
+ isAdmin?
+
+
+
this.Createsign()}>创建签到
+
+ :""
+ }
+
+
+
+ :
+ // 签到详情
+ this.qiandaoxiangq(b)}
+ >
+
+ }
+
+
+
+ )
+ }
+}
+export default Students_signin;
diff --git a/public/react/src/modules/courses/videostatistics/Videostatistics.js b/public/react/src/modules/courses/videostatistics/Videostatistics.js
new file mode 100644
index 000000000..52d69b0fb
--- /dev/null
+++ b/public/react/src/modules/courses/videostatistics/Videostatistics.js
@@ -0,0 +1,94 @@
+import React,{ Component } from "react";
+import axios from 'axios';
+import '../signin/css/signincdi.css';
+import Videostatisticscom from './component/Videostatisticscom';
+import Videostatisticslist from './component/Videostatisticslist';
+import Videostatisticscomtwo from './component/Videostatisticscomtwo';
+
+
+//在线学习
+class Videostatistics extends Component{
+ constructor(props){
+ super(props);
+ this.state={
+ watch_staticsdata:[],
+ tisticsbool:false,
+ tisid:null,
+ }
+
+
+ }
+
+ componentDidMount() {
+ this.togetdatas();
+ }
+ details=()=>{
+
+ }
+
+ togetdatas(){
+ const CourseId=this.props.match.params.coursesId;
+ let url=`/courses/${CourseId}/watch_statics.json`;
+ axios.get(url).then((response) => {
+ if(response){
+ this.setState({
+ watch_staticsdata:response.data,
+ })
+
+ }
+
+ }).catch((error) => {
+
+
+ });
+ }
+
+ tisticsbools=(bool,id)=>{
+ this.setState({
+ tisticsbool:bool,
+ tisid:id,
+ })
+ }
+
+
+ render(){
+ let {watch_staticsdata,tisticsbool,tisid}= this.state;
+
+ return(
+
+
+ {
+ tisticsbool===false?
+
+
+
this.props.statisticsy(false)}>
+
+
返回
+
+
+
+
+
+
+
+
+ this.tisticsbools(b,id)}>
+
+
+
+
+ :
+
this.tisticsbools(b,id)}>
+ }
+
+
+
+ )
+ }
+}
+export default Videostatistics;
diff --git a/public/react/src/modules/courses/videostatistics/component/Videostatisticscom.js b/public/react/src/modules/courses/videostatistics/component/Videostatisticscom.js
new file mode 100644
index 000000000..457c6d1f3
--- /dev/null
+++ b/public/react/src/modules/courses/videostatistics/component/Videostatisticscom.js
@@ -0,0 +1,103 @@
+import React, {Component} from "react";
+import '../../signin/css/signincdi.css';
+import {Progress, message} from 'antd';
+import {getImageUrl} from 'educoder';
+import axios from 'axios';
+
+
+
+//条目
+class Videostatisticscom extends Component {
+ //条目组件
+ constructor(props) {
+ super(props);
+
+ this.state = {}
+ }
+
+ componentDidMount() {
+
+ }
+
+ componentDidUpdate = (prevProps) => {
+
+
+ }
+
+
+
+ render() {
+
+ return (
+
+
+
+
+
视频统计总览
+
播放数据从{this.props.watch_staticsdata&&this.props.watch_staticsdata.begin_at?this.props.watch_staticsdata.begin_at:0}开始统计
+
+
+
+
+
+
观看总人数(人)
+
{this.props.watch_staticsdata&&this.props.watch_staticsdata.people_num?this.props.watch_staticsdata.people_num:0}
+
+
+
+
+
+
+
+
观看总人次(次)
+
{this.props.watch_staticsdata&&this.props.watch_staticsdata.freq?this.props.watch_staticsdata.freq:0}
+
+
+
+
+
+
总观看时长(时)
+
{this.props.watch_staticsdata&&this.props.watch_staticsdata.total_duration?this.props.watch_staticsdata.total_duration:0}
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+ }
+}
+
+export default Videostatisticscom;
diff --git a/public/react/src/modules/courses/videostatistics/component/Videostatisticscomtwo.js b/public/react/src/modules/courses/videostatistics/component/Videostatisticscomtwo.js
new file mode 100644
index 000000000..764ddcb1f
--- /dev/null
+++ b/public/react/src/modules/courses/videostatistics/component/Videostatisticscomtwo.js
@@ -0,0 +1,504 @@
+import React, {Component} from "react";
+import '../../signin/css/signincdi.css';
+import {Pagination, Table, Menu, Dropdown} from 'antd';
+import {getImageUrl, sortDirections} from 'educoder';
+import axios from 'axios';
+import LoadingSpin from "../../../../common/LoadingSpin";
+import NoneDatas from "../../signin/component/NoneDatas";
+
+
+//条目
+class Videostatisticscomtwo extends Component {
+ //条目组件
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ data: [],
+ page: 1,
+ limit: 10,
+ members_count: 0,
+ columnsstu: [
+ {
+ title: '序号',
+ dataIndex: 'number',
+ key: 'number',
+ align: "center",
+ className: 'font-14',
+ width: '50px',
+ render: (text, record) => (
+ {record.number}
+ ),
+ },
+ {
+ title: '用户',
+ dataIndex: 'user_name',
+ key: 'user_name',
+ align: "center",
+ className: 'font-14 maxnamewidth100s',
+ width: '100px',
+ render: (text, record) => (
+ {record.user_name}
+ ),
+ },
+ {
+ title: '视频是否看完',
+ dataIndex: 'is_finished',
+ key: 'is_finished',
+ align: "center",
+ className: 'font-14',
+ width: '98px',
+ render: (text, record) => (
+ {record.is_finished === true ?
+ 是 : 否}
+ ),
+ },
+ {
+ title: '视频累计观看时长',
+ dataIndex: 'total_duration',
+ key: 'total_duration',
+ align: "center",
+ className: 'font-14 maxnamewidth150s',
+ width: '150px',
+ sorter: true,
+ sortDirections: sortDirections,
+ render: (text, record) => (
+ {record.total_duration}
+ ),
+ },
+ {
+ title: '累计观看次数(次)',
+ dataIndex: 'feq',
+ key: 'feq',
+ align: "center",
+ className: 'font-14 maxnamewidth100s',
+ width: '100px',
+ sorter: true,
+ sortDirections: sortDirections,
+ render: (text, record) => (
+ {record.feq}
+ ),
+ },
+ {
+ title: '最早观看时间',
+ dataIndex: 'start_at',
+ key: 'start_at',
+ align: "center",
+ className: 'font-14 maxnamewidth100s',
+ width: '100px',
+ render: (text, record) => (
+ {record.start_at}
+ ),
+ },
+ {
+ title: '最后观看时间',
+ dataIndex: 'end_at',
+ key: 'end_at',
+ align: "center",
+ className: 'font-14 maxnamewidth100s',
+ width: '100px',
+ render: (text, record) => (
+ {record.end_at}
+ ),
+ }
+ ],
+ loading: false,
+ order: undefined,
+ course_groups: [],
+ fbbool: false,
+ groupsid: null,
+ }
+ }
+
+ componentDidMount() {
+ this.setState({
+ order: undefined
+ })
+ if (this.props.isAdmin()) {
+ //老师
+ const CourseId = this.props.match.params.coursesId;
+
+ var data = {
+ id: CourseId,
+ page: this.state.page,
+ }
+ this.getdatas(data);
+
+ } else {
+ //学生
+ var data = {
+ page: this.state.page,
+ }
+ this.getdatas(data);
+ }
+ this.fenbans();
+ }
+
+ componentDidUpdate = (prevProps) => {
+
+
+ }
+
+ //分班
+ fenbans = () => {
+ const CourseId = this.props.match.params.coursesId;
+ let url = `/courses/${CourseId}/course_groups.json`;
+ axios.get(url).then((response) => {
+ if (response) {
+ console.log("分班");
+ console.log("response");
+ console.log(response);
+ this.setState({
+ course_groups: response.data.course_groups,
+ current_group_id: response.data.current_group_id,
+ none_group_member_count: response.data.none_group_member_count,
+ group_count: response.data.group_count,
+ })
+ }
+
+ }).catch((error) => {
+
+ });
+ }
+
+ //学生
+ getdatas = (data) => {
+ this.setState({
+ loading: true
+ })
+ const CourseId = this.props.match.params.coursesId;
+ let url = "";
+ if (this.props.isAdmin()) {
+ url = `/course_videos/${this.props.tisid}/watch_histories.json`;
+ } else {
+ url = `/courses/${CourseId}/own_watch_histories.json`;
+ }
+ axios.get(url, {params: data}).then((response) => {
+ if (response) {
+ if (response.data) {
+ if (response.data.data.length > 0) {
+ let datalists = [];
+ for (var i = 0; i < response.data.data.length; i++) {
+ datalists.push({
+ number: (parseInt(this.state.page) - 1) * parseInt(this.state.limit) + (i + 1),
+ user_name: response.data.data[i].user_name,
+ is_finished: response.data.data[i].is_finished,
+ total_duration: response.data.data[i].total_duration,
+ feq: response.data.data[i].feq,
+ start_at: response.data.data[i].start_at,
+ end_at: response.data.data[i].end_at,
+ })
+ }
+
+ this.setState({
+ data: datalists,
+ members_count: response.data.count,
+ })
+ } else {
+ this.setState({
+ data: [],
+ members_count: response.data.count,
+ })
+ }
+ } else {
+ this.setState({
+ data: [],
+ members_count: response.data.count,
+ })
+ }
+
+
+ }
+ this.setState({
+ loading: false
+ })
+ }).catch((error) => {
+ this.setState({
+ loading: false
+ })
+ });
+ }
+
+
+ paginationonChange = (pageNumber) => {
+ this.setState({
+ page: pageNumber,
+ })
+ let data = {}
+ if (this.props.isAdmin()) {
+ //老师
+ const CourseId = this.props.match.params.coursesId;
+ data = {
+ id: CourseId,
+ page: pageNumber,
+ group_id: this.state.groupsid,
+ order: this.state.order,
+ }
+ } else {
+ //学生
+ data = {
+ page: pageNumber,
+ order: this.state.order,
+ }
+ }
+ this.getdatas(data);
+ }
+ fenbanone = () => {
+ if (this.state.fbbool === false) {
+ this.setState({
+ fbbool: true
+ })
+ } else {
+ this.setState({
+ fbbool: false
+ })
+ }
+ }
+ setcourse_groups = (id) => {
+ this.setState({
+ groupsid: id
+ })
+//老师
+ const CourseId = this.props.match.params.coursesId;
+
+ var data = {};
+ if (id) {
+ data = {
+ id: CourseId,
+ page: this.state.page,
+ group_id: id
+ }
+
+ } else {
+ data = {
+ id: CourseId,
+ page: this.state.page
+ }
+ }
+ this.getdatas(data);
+ }
+
+ //实训作业tbale 列表塞选数据
+ table1handleChange = (pagination, filters, sorter) => {
+ if (JSON.stringify(sorter) === "{}") {
+ //没有选择
+ } else {
+ try {
+ //学生学号排序
+ if (sorter.columnKey === "total_duration" || sorter.columnKey === "feq") {
+ let mysorder = "";
+ if (sorter.order === "ascend") {
+ if (sorter.columnKey === "total_duration") {
+ mysorder = "total_duration-asc";
+ } else {
+ mysorder = "freq-asc";
+
+ }
+ //升序
+ let data = {}
+ if (this.props.isAdmin()) {
+ //老师
+ const CourseId = this.props.match.params.coursesId;
+ if (this.state.groupsid) {
+ data = {
+ id: CourseId,
+ page: this.state.page,
+ group_id: this.state.groupsid,
+ order: mysorder,
+ }
+ } else {
+ data = {
+ id: CourseId,
+ page: this.state.page,
+ order: mysorder,
+ }
+ }
+ } else {
+ //学生
+ data = {
+ page: this.state.page,
+ order: mysorder,
+ }
+ }
+
+ this.getdatas(data);
+ this.setState({
+ order: mysorder,
+ })
+ } else if (sorter.order === "descend") {
+ if (sorter.columnKey === "total_duration") {
+ mysorder = "total_duration-desc";
+
+ } else {
+ mysorder = "freq-desc";
+
+ }
+ //降序
+ let data = {}
+ if (this.props.isAdmin()) {
+ //老师
+ const CourseId = this.props.match.params.coursesId;
+ if (this.state.groupsid) {
+ data = {
+ id: CourseId,
+ page: this.state.page,
+ group_id: this.state.groupsid,
+ order: mysorder,
+ }
+ } else {
+ data = {
+ id: CourseId,
+ page: this.state.page,
+ order: mysorder,
+ }
+ }
+ } else {
+ //学生
+ data = {
+ page: this.state.page,
+ order: mysorder,
+ }
+ }
+
+ this.getdatas(data);
+ this.setState({
+ order: mysorder,
+ })
+
+
+ }
+ }
+ } catch (e) {
+
+ }
+
+ }
+
+ }
+
+
+ render() {
+ let {loading, data, page, limit, members_count, columnsstu, fbbool, course_groups} = this.state;
+ const isAdmin = this.props.isAdmin();
+
+ const menu = (
+
+ );
+ return (
+
+
+
+
+
视频名称视频名称…
+
+
this.props.tisticsbools(false, null)}>
+ 视频统计总览
+
+ {
+ isAdmin === true ?
+
this.fenbanone()}>
+ trigger.parentNode} overlay={menu}
+ placement="bottomCenter">
+
+ 分班
+ {
+ fbbool === true ?
+
+ :
+
+ }
+
+
+
+ :
+ ""
+ }
+
+
+
+
+
+
+ {
+ loading === true ?
+
+
+
+ :
+
+ {
+ data.length === 0 ?
+
+
+
+ :
+
+ }
+
+
+
+ }
+
+
+
+
+
+ {
+ data && data.length > 0 ?
+
+ : ""
+ }
+
+
+
+
+
+ )
+ }
+}
+
+export default Videostatisticscomtwo;
diff --git a/public/react/src/modules/courses/videostatistics/component/Videostatisticslist.js b/public/react/src/modules/courses/videostatistics/component/Videostatisticslist.js
new file mode 100644
index 000000000..637ec306c
--- /dev/null
+++ b/public/react/src/modules/courses/videostatistics/component/Videostatisticslist.js
@@ -0,0 +1,302 @@
+import React, {Component} from "react";
+import '../../signin/css/signincdi.css';
+import {Pagination,Table} from 'antd';
+import {getImageUrl,sortDirections} from 'educoder';
+import axios from 'axios';
+import LoadingSpin from "../../../../common/LoadingSpin";
+import NoneDatas from "../../signin/component/NoneDatas";
+
+
+//条目
+class Videostatisticslist extends Component {
+ //条目组件
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ columnsstu: [
+ {
+ title: '序号',
+ dataIndex: 'number',
+ key: 'number',
+ align: "center",
+ className: 'font-14',
+ width: '90px',
+ render: (text, record) => (
+ {record.number}
+ ),
+ },
+ {
+ title: '视频名称',
+ dataIndex: 'title',
+ key: 'title',
+ align: "center",
+ className: 'font-14 maxnamewidth150s',
+ width: '150px',
+ render: (text, record) => (
+ {record.title}
+ ),
+ },
+ {
+ title: '观看人数(人)',
+ dataIndex: 'people_num',
+ key: 'people_num',
+ align: "center",
+ className: 'font-14',
+ width: '98px',
+ sorter: true,
+ sortDirections: sortDirections,
+ render: (text, record) => (
+ {record.people_num}
+ ),
+ },
+ {
+ title: '累计观看时长',
+ dataIndex: 'total_time',
+ key: 'total_time',
+ align: "center",
+ className: 'font-14 maxnamewidth150s',
+ width: '150px',
+ sorter: true,
+ sortDirections: sortDirections,
+ render: (text, record) => (
+ {record.total_time}
+ ),
+ },
+ {
+ title: '发布人',
+ dataIndex: 'user_name',
+ key: 'user_name',
+ align: "center",
+ className: 'font-14 maxnamewidth100s',
+ width: '100px',
+ render: (text, record) => (
+ {record.user_name}
+ ),
+ },
+ {
+ title: '详情',
+ dataIndex: 'id',
+ key: 'id',
+ align: "center",
+ className: 'font-14',
+ width: '90px',
+ render: (text, record) => (
+ this.props.tisticsbools(true,record.id)}>详情
+ ),
+ }
+ ],
+ loading:false,
+ data:[],
+ page:1,
+ limit:10,
+ members_count:0,
+ order:undefined,
+ }
+ }
+
+ componentDidMount() {
+ let data={
+ page:1,
+ order:this.state.order
+ }
+ this.togetdatas(data);
+
+ }
+
+ componentDidUpdate = (prevProps) => {
+
+
+ }
+ paginationonChange = (pageNumber) => {
+ this.setState({
+ page: pageNumber,
+ })
+ let data={
+ page:pageNumber,
+ order:this.state.order
+ }
+ this.togetdatas(data);
+ }
+
+
+ togetdatas(data){
+ this.setState({
+ loading:true
+ })
+ const CourseId=this.props.match.params.coursesId;
+ let url=`/courses/${CourseId}/watch_video_histories.json`;
+ axios.get(url,{params:data
+ }).then((response) => {
+ if (response) {
+ if (response.data) {
+ if (response.data.videos.length > 0) {
+ let datalists = [];
+ for (var i = 0; i < response.data.videos.length; i++) {
+ datalists.push({
+ number: (parseInt(this.state.spage) - 1) * parseInt(this.state.limit) + (i + 1),
+ title: response.data.videos[i].title,
+ people_num: response.data.videos[i].people_num,
+ total_time: response.data.videos[i].total_time,
+ user_name: response.data.videos[i].user_name,
+ id: response.data.videos[i].id,
+ })
+ }
+
+ this.setState({
+ data: datalists,
+ members_count: response.data.count,
+ })
+ } else {
+ this.setState({
+ data: [],
+ members_count: response.data.count,
+ })
+ }
+ } else {
+ this.setState({
+ data: [],
+ members_count: response.data.count,
+ })
+ }
+
+
+ }
+
+
+
+ this.setState({
+ loading:false
+ })
+ }).catch((error) => {
+ this.setState({
+ loading:false
+ })
+ });
+ }
+
+
+ //实训作业tbale 列表塞选数据
+ table1handleChange = (pagination, filters, sorter) => {
+ if (JSON.stringify(sorter) === "{}") {
+ //没有选择
+ } else {
+ try {
+ //学生学号排序
+ if (sorter.columnKey === "people_num"||sorter.columnKey === "total_time") {
+ let mysorder="";
+ if (sorter.order === "ascend") {
+ if(sorter.columnKey === "people_num"){
+ mysorder="people_num-asc";
+ }else{
+ mysorder="total_time-asc";
+
+ }
+ //升序
+ let data={
+ page:this.state.page,
+ order:mysorder
+ }
+ this.togetdatas(data);
+ this.setState({
+ order: mysorder,
+ })
+ } else if (sorter.order === "descend") {
+ if(sorter.columnKey === "people_num"){
+ mysorder="people_num-desc";
+ }else{
+ mysorder="total_time-desc";
+
+ }
+ //降序
+ let data={
+ page:this.state.page,
+ order:mysorder
+ }
+ this.togetdatas(data);
+ this.setState({
+ order: mysorder,
+ })
+ }
+ }
+ } catch (e) {
+
+ }
+
+ }
+
+ }
+
+
+
+ render() {
+ let {loading,data,columnsstu,page,members_count,limit}=this.state;
+ return (
+
+
+
+
+
+ {
+ loading===true?
+
+
+
+ :
+
+ {
+ data.length===0?
+
+
+
+ :
+
+ }
+
+
+
+ }
+
+
+
+
+ {
+ data&&data.length>0?
+
+ :""
+ }
+
+
+
+
+
+ )
+ }
+}
+
+export default Videostatisticslist;
diff --git a/public/react/src/modules/login/Trialapplication.js b/public/react/src/modules/login/Trialapplication.js
index be0b18edb..5cb181663 100644
--- a/public/react/src/modules/login/Trialapplication.js
+++ b/public/react/src/modules/login/Trialapplication.js
@@ -386,7 +386,7 @@ class Trialapplication extends Component {
{
isRenders === false ? "" :
-
+
-

-
修改头像
+

+
修改头像
);
}
diff --git a/public/react/src/modules/user/usersInfo/video/InfosVideo.css b/public/react/src/modules/user/usersInfo/video/InfosVideo.css
index fb78f9e85..a03a2c6f6 100644
--- a/public/react/src/modules/user/usersInfo/video/InfosVideo.css
+++ b/public/react/src/modules/user/usersInfo/video/InfosVideo.css
@@ -70,6 +70,7 @@
}
.videoItem .time {
+ height: 15px;
color: #C0C4CC;
}
.videoItem .square-main .buttonRow .dianjilianicon{
diff --git a/public/react/src/modules/user/usersInfo/video/VideoInReviewItem.js b/public/react/src/modules/user/usersInfo/video/VideoInReviewItem.js
index 4e0ca8fb2..299af0d08 100644
--- a/public/react/src/modules/user/usersInfo/video/VideoInReviewItem.js
+++ b/public/react/src/modules/user/usersInfo/video/VideoInReviewItem.js
@@ -1,6 +1,6 @@
import React, { useState, useEffect, useContext, memo } from 'react';
import { Progress, Input, Tooltip , Spin } from 'antd'
-import { getUrl2, isDev, CBreadcrumb, ActionBtn, ThemeContext } from 'educoder'
+import { getUrl2, isDev, CBreadcrumb, ActionBtn, ThemeContext,formatSeconds} from 'educoder'
import axios from 'axios'
import moment from 'moment'
import playIcon from './images/play.png'
@@ -21,7 +21,7 @@ const clipboardMap = {}
function VideoInReviewItem (props) {
const theme = useContext(ThemeContext);
const { history, file_url , play_url , cover_url , transcoded , title, created_at, published_at, isReview, id
- , onEditVideo, onMaskClick, getCopyText, showNotification,vv,play_duration,operation , deleteVideo , moveVideo ,link} = props;
+ , onEditVideo, onMaskClick, getCopyText, showNotification,vv,play_duration,operation , deleteVideo , moveVideo ,link, people_num,total_time} = props;
useEffect(()=> {
if (!isReview) {
_clipboard = new ClipboardJS(`.copybtn_item_${id}`);
@@ -37,6 +37,9 @@ function VideoInReviewItem (props) {
}
}
}, [])
+
+
+
const username = props.match.params.username
function toList() {
history.push(`/users/${username}/videos`)
@@ -60,7 +63,7 @@ function VideoInReviewItem (props) {
{!isReview && !link && transcoded &&
onMaskClick(props)}>

- {play_duration===0?"":
累计学习时长:{play_duration} h
}
+ {/* {play_duration===0?"":
累计学习时长:{play_duration} h
} */}
}
@@ -69,16 +72,22 @@ function VideoInReviewItem (props) {
title={title && title.length > 20 ? title : ''}
>{title}
-
-
{moment(published_at || created_at).format('YYYY-MM-DD HH:mm:ss')}
+ {/*
累计学习时长:{play_duration} h
*/}
+ {/*
{moment(published_at || created_at).format('YYYY-MM-DD HH:mm:ss')}{people_num} */}
+ {link ?
:
累计学习时长:{
+ formatSeconds(total_time)}
+ {/* total_time<60?total_time+' s':total_time/60<60?(total_time/60).toFixed(0)+' min':(total_time/3600).toFixed(1)+ ' h' */}
+ }
{/* 2019-09-01 10:00:22 */}
- {!vv || (vv && vv)===0 ? "" :
-
- } {!vv || (vv && vv)===0?"":vv}
+ {!people_num || (people_num && people_num)===0 ? "" :
+ {!people_num || (people_num && people_num)===0?"":people_num}
+ }
+
+
{
isReview !== true && moveVideo &&
diff --git a/public/stylesheets/educoder/iconfont/demo_index.html b/public/stylesheets/educoder/iconfont/demo_index.html
index 281ac40d0..7a6d6b5e8 100644
--- a/public/stylesheets/educoder/iconfont/demo_index.html
+++ b/public/stylesheets/educoder/iconfont/demo_index.html
@@ -30,6 +30,84 @@
+ -
+
+
返回
+ 
+
+
+ -
+
+
统计
+ 
+
+
+ -
+
+
签到-02
+ 
+
+
+ -
+
+
下箭头
+ 
+
+
+ -
+
+
签到-01
+ 
+
+
+ -
+
+
移动
+ 
+
+
+ -
+
+
下移2
+ 
+
+
+ -
+
+
上移2
+ 
+
+
+ -
+
+
下移
+ 
+
+
+ -
+
+
上移
+ 
+
+
+ -
+
+
编辑
+ 
+
+
+ -
+
+
删除
+ 
+
+
+ -
+
+
选择
+ 
+
+
-
编辑
@@ -2012,6 +2090,123 @@
+ -
+
+
+ 返回
+
+ .icon-fanhui
+
+
+
+ -
+
+
+ 统计
+
+ .icon-tongji1
+
+
+
+ -
+
+
+ 签到-02
+
+ .icon-qiandao-1
+
+
+
+ -
+
+
+ 下箭头
+
+ .icon-xiajiantou2
+
+
+
+ -
+
+
+ 签到-01
+
+ .icon-qiandao-
+
+
+
+ -
+
+
+ 移动
+
+ .icon-yidong
+
+
+
+ -
+
+
+ 下移2
+
+ .icon-xiayi1
+
+
+
+ -
+
+
+ 上移2
+
+ .icon-shangyi1
+
+
+
+ -
+
+
+ 下移
+
+ .icon-xiayi
+
+
+
+ -
+
+
+ 上移
+
+ .icon-shangyi
+
+
+
+ -
+
+
+ 编辑
+
+ .icon-bianji5
+
+
+
+ -
+
+
+ 删除
+
+ .icon-shanchu3
+
+
+
+ -
+
+
+ 选择
+
+ .icon-xuanze
+
+
+
-
@@ -4939,6 +5134,110 @@
+ -
+
+
返回
+ #icon-fanhui
+
+
+ -
+
+
统计
+ #icon-tongji1
+
+
+ -
+
+
签到-02
+ #icon-qiandao-1
+
+
+ -
+
+
下箭头
+ #icon-xiajiantou2
+
+
+ -
+
+
签到-01
+ #icon-qiandao-
+
+
+ -
+
+
移动
+ #icon-yidong
+
+
+ -
+
+
下移2
+ #icon-xiayi1
+
+
+ -
+
+
上移2
+ #icon-shangyi1
+
+
+ -
+
+
下移
+ #icon-xiayi
+
+
+ -
+
+
上移
+ #icon-shangyi
+
+
+ -
+
+
编辑
+ #icon-bianji5
+
+
+ -
+
+
删除
+ #icon-shanchu3
+
+
+ -
+
+
选择
+ #icon-xuanze
+
+
-