合并阿里云

courseware
杨树林 5 years ago
commit cdbfadb9e6

@ -2,6 +2,7 @@ class AttendancesController < ApplicationController
before_action :require_login
before_action :find_course, only: [:index, :statistics]
before_action :find_attendance, except: [:index, :statistics]
before_action :user_course_identity
def index
@ -66,9 +67,53 @@ class AttendancesController < ApplicationController
@avg_leave_rate = data[:avg_leave_rate]
end
def edit
@groups = @course.course_groups.where(id: @attendance.course_attendance_groups.pluck(:course_group_id))
end
def update
tip_exception(403, "") unless @user_course_identity < Course::PROFESSOR || @attendance.user_id == current_user.id
a_end_time = "#{@attendance.attendance_date} #{@attendance.end_time}".to_time
new_end_time = "#{params[:attendance_date]} #{params[:end_time]}".to_time
@attendance.update!(update_params)
# 如果历史签到变为了正在签到,将未创建的学生签到数据补上
if a_end_time < Time.current && new_end_time > Time.current
create_absence_student_data
end
render_ok
end
private
def find_attendance
@attendance = CourseAttendance.find params[:id]
@course = @attendance.course
end
def update_params
params.permit(:name, :mode, :attendance_date, :start_time, :end_time)
end
def create_absence_student_data
group_ids = @attendance.course_attendance_groups.pluck(:course_group_id)
if group_ids.include?(0)
students = @course.students
else
students = @course.students.where(course_group_id: group_ids)
end
none_users = students.where.not(user_id: @attendance.course_member_attendances.pluck(:user_id))
attrs = %i[course_attendance_id user_id course_member_id course_id course_group_id created_at updated_at]
same_attrs = {course_attendance_id: attendance.id, course_id: course.id}
CourseMemberAttendance.bulk_insert(*attrs) do |worker|
none_users.each do |student|
next if @attendance.course_member_attendances.exists?(user_id: student.user_id)
worker.add same_attrs.merge(user_id: student.user_id, course_member_id: student.id, course_group_id: student.course_group_id)
end
end
end
end

@ -25,7 +25,7 @@ class CourseVideosController < ApplicationController
course_video = CourseVideo.find(@video.id)
@watch_course_videos = course_video.watch_course_videos.joins("
JOIN watch_video_histories ON watch_video_histories.watch_course_video_id = watch_course_videos.id
JOIN watch_video_histories ON watch_video_histories.watch_course_video_id = watch_course_videos.id AND watch_video_histories.end_at IS NOT NULL
JOIN course_members ON course_members.user_id = watch_course_videos.user_id AND course_members.course_id = #{@course.id} AND role = 4
").group("watch_video_histories.watch_course_video_id").where("watch_course_videos.end_at IS NOT NULL").select("watch_course_videos.id")
@ -35,7 +35,7 @@ class CourseVideosController < ApplicationController
@watch_course_videos = @watch_course_videos.where("course_members.course_group_id = ?", params[:group_id])
end
@watch_course_videos = @watch_course_videos.select("count(watch_video_histories.id) AS freq, watch_course_videos.*")
@watch_course_videos = @watch_course_videos.select("count(watch_course_videos.course_video_id) AS freq, watch_course_videos.*")
if params[:order].present?
key = params[:order].split("-")

@ -1491,10 +1491,11 @@ class CoursesController < ApplicationController
@videos = CourseVideo.joins("
JOIN videos ON course_videos.course_id = #{@course.id} AND videos.id = course_videos.video_id
LEFT JOIN (
SELECT watch_course_videos.course_video_id, SUM(watch_course_videos.total_duration) AS time, COUNT(watch_course_videos.course_video_id) AS num
SELECT watch_course_videos.course_video_id, SUM(watch_course_videos.total_duration) AS time, COUNT(watch_video_histories.watch_course_video_id) AS num
FROM watch_course_videos
JOIN course_videos ON course_videos.id = watch_course_videos.course_video_id AND watch_course_videos.end_at IS NOT NULL
JOIN course_members ON course_members.user_id = watch_course_videos.user_id AND course_members.course_id = #{@course.id} AND role = 4
JOIN watch_video_histories ON watch_course_videos.id = watch_video_histories.watch_course_video_id AND watch_video_histories.end_at IS NOT NULL
WHERE course_videos.course_id = #{@course.id}
GROUP BY watch_course_videos.course_video_id
) AS hisotries ON hisotries.course_video_id = course_videos.id").select("course_videos.id")
@ -1521,16 +1522,19 @@ class CoursesController < ApplicationController
JOIN videos ON course_videos.course_id = #{@course.id} AND videos.id = course_videos.video_id
JOIN watch_course_videos ON course_videos.id = watch_course_videos.course_video_id AND watch_course_videos.user_id = #{current_user.id}
JOIN (
SELECT watch_course_videos.course_video_id, COUNT(watch_course_videos.course_video_id) AS num
SELECT watch_course_videos.course_video_id, COUNT(watch_video_histories.watch_course_video_id) AS num
FROM watch_course_videos
JOIN course_videos ON course_videos.id = watch_course_videos.course_video_id
JOIN course_members ON course_members.user_id = watch_course_videos.user_id AND course_members.course_id = #{@course.id} AND role = 4
JOIN watch_video_histories ON watch_course_videos.id = watch_video_histories.watch_course_video_id AND watch_video_histories.end_at IS NOT NULL
WHERE course_videos.course_id = #{@course.id} AND watch_course_videos.user_id = #{current_user.id} AND watch_course_videos.end_at IS NOT NULL
GROUP BY watch_course_videos.course_video_id
) AS hisotries ON hisotries.course_video_id = course_videos.id").select("course_videos.id")
@count = @videos.count
@videos = @videos.includes(video: :user)
if params[:order].present?
key = params[:order].split("-")
if ["freq", 'total_duration'].include?(key.first) && ["desc", "asc"].include?(key.last)
@ -1538,24 +1542,32 @@ class CoursesController < ApplicationController
end
end
@videos = @videos.select("course_videos.id, watch_course_videos.start_at, watch_course_videos.total_duration, watch_course_videos.end_at, watch_course_videos.is_finished, videos.title, IFNULL(hisotries.num,0) AS freq")
@videos = @videos.select("course_videos.id, course_videos.video_id, watch_course_videos.start_at, watch_course_videos.total_duration, watch_course_videos.end_at, watch_course_videos.is_finished, videos.title, IFNULL(hisotries.num,0) AS freq")
@videos = paginate @videos
end
# 课堂视频的统计总览
def watch_statics
course_videos = @course.course_videos.joins(:watch_course_videos).joins("
JOIN course_members ON course_members.user_id = watch_course_videos.user_id AND course_members.course_id = #{@course.id} AND role = 4
").where("watch_course_videos.end_at IS NOT NULL")
@total_duration = course_videos.sum(:total_duration).round(0)
@frequencies = course_videos.joins("JOIN watch_video_histories ON watch_course_videos.id = watch_video_histories.watch_course_video_id").count(:id)
@people_num = course_videos.count(:id)
course_videos = @course.course_videos.joins(:watch_course_videos).joins("JOIN course_members ON course_members.user_id = watch_course_videos.user_id AND course_members.course_id = #{@course.id} AND role = 4").where("watch_course_videos.end_at IS NOT NULL")
if params[:all].present?
return normal_status(403, "你没有权限操作") unless current_user.teacher_of_course?(@course)
@total_duration = course_videos.sum(:total_duration).round(0)
@frequencies = course_videos.joins("JOIN watch_video_histories ON watch_course_videos.id = watch_video_histories.watch_course_video_id AND watch_video_histories.end_at IS NOT NULL").count(:id)
@num = course_videos.count(:id)
else
course_videos = course_videos.where("course_members.user_id = #{current_user.id}")
@total_duration = course_videos.sum(:total_duration).round(0)
@frequencies = course_videos.joins("JOIN watch_video_histories ON watch_course_videos.id = watch_video_histories.watch_course_video_id AND watch_video_histories.end_at IS NOT NULL").count(:id)
@num = course_videos.count(:id)
end
render json: {
total_duration: @total_duration,
freq: @frequencies,
people_num: @people_num,
begin_at: '2020-03-13 24:00'
freq: @frequencies,
num: @num,
begin_at: '2020-03-13 24:00'
}
end

@ -32,8 +32,7 @@ class FilesController < ApplicationController
end
end
@attachments = @attachments.includes(author: [:user_extension, :course_members])
.ordered(sort: sort.to_i, sort_type: sort_type.strip)
@attachments = @attachments.ordered(sort: sort.to_i, sort_type: sort_type.strip)
@total_count = @attachments.size
@unlink_count = @attachments.no_link.size
@ -59,7 +58,8 @@ class FilesController < ApplicationController
@attachments = @attachments.no_link
end
@attachments = @attachments.page(@page).per(@page_size)
@attachments = @attachments.includes(:course_second_category, author: [:user_extension, :course_members])
.page(@page).per(@page_size)
end
def bulk_publish

@ -477,6 +477,8 @@ class StudentWorksController < ApplicationController
@user_evaluate_count = 0
end
@view_tpi = ((@user_course_identity < Course::STUDENT && current_user.is_certification_teacher) || current_user.admin_or_business?) && @work.myshixun.present?
# 图形效率图的数据
@echart_data = student_efficiency(@homework, @work) if @work.myshixun
end

@ -28,6 +28,7 @@ class Attachment < ApplicationRecord
scope :no_link, -> {where(link: nil)}
validates_length_of :description, maximum: 100, message: "不能超过100个字符"
validates :link, format: { with: CustomRegexp::URL, message: "必须为网址超链接" }, allow_blank: true
DCODES = %W(2 3 4 5 6 7 8 9 a b c f e f g h i j k l m n o p q r s t u v w x y z)

@ -0,0 +1,4 @@
json.(@attendance, :name, :mode, :attendance_date, :start_time, :end_time)
json.groups @groups do |group|
json.(group, :id, :name)
end

@ -2,7 +2,7 @@ json.has_course_groups @has_course_groups
json.course_modules do
json.array! @course_modules do |course_module|
json.value course_module.id
json.title course_module.module_name
json.title course_module.module_name.to_s + "(根目录)"
json.children course_module.first_categories do |category|
json.title category.name
json.value category.id

@ -1,7 +1,7 @@
json.data do
json.array! @videos.each do |d|
json.title d.title
json.user_name @current_user&.real_name
json.user_name d.video.user&.real_name
json.is_finished d.is_finished ? true : false
json.total_duration d.total_duration.round(0)
json.freq d['freq']

@ -17,7 +17,7 @@ json.data do
end
# json.partial! "files/course_groups", attachment_group_settings: attachment.attachment_group_settings
json.category_id attachment.course_second_category_id
unless @parent_category_id.present? && @parent_category_id != 0
if (@parent_category_id.blank? || @parent_category_id != 0) && attachment.course_second_category&.parent_id.to_i != 0
json.category_name attachment.course_second_category&.name
end
end

@ -87,4 +87,6 @@ if @shixun
end
end
json.view_tpi @view_tpi

@ -64,6 +64,7 @@ zh-CN:
description: '章节描述'
attachment:
description: '资源描述'
link: '链接'
message:
subject: '标题'
message_detail:

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

@ -30,6 +30,12 @@
<div class="content unicode" style="display: block;">
<ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont">&#xe73a;</span>
<div class="name">返回左键头</div>
<div class="code-name">&amp;#xe73a;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe739;</span>
<div class="name">返回</div>
@ -2090,6 +2096,15 @@
<div class="content font-class">
<ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont icon-zuojiantou1"></span>
<div class="name">
返回左键头
</div>
<div class="code-name">.icon-zuojiantou1
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-fanhui"></span>
<div class="name">
@ -5134,6 +5149,14 @@
<div class="content symbol">
<ul class="icon_lists dib-box">
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-zuojiantou1"></use>
</svg>
<div class="name">返回左键头</div>
<div class="code-name">#icon-zuojiantou1</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-fanhui"></use>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -5,6 +5,13 @@
"css_prefix_text": "icon-",
"description": "",
"glyphs": [
{
"icon_id": "13511742",
"name": "返回左键头",
"font_class": "zuojiantou1",
"unicode": "e73a",
"unicode_decimal": 59194
},
{
"icon_id": "13458315",
"name": "返回",

@ -20,6 +20,9 @@ Created by iconfont
/>
<missing-glyph />
<glyph glyph-name="zuojiantou1" unicode="&#59194;" d="M832.503909-127.983381a63.919062 63.919062 0 0 0-38.990629 12.144622L151.765893 340.543347a51.13525 51.13525 0 0 0 0 85.651544l639.190625 457.021297a67.754206 67.754206 0 0 0 87.569116-8.309479 50.496059 50.496059 0 0 0-9.58786-77.342065L289.831068 383.369119l581.663469-412.277953a50.496059 50.496059 0 0 0 9.587859-77.342066 63.919062 63.919062 0 0 0-48.578487-21.732481z" horiz-adv-x="1024" />
<glyph glyph-name="fanhui" unicode="&#59193;" d="M590.769231-107.362462H315.076923c-31.507692 0-63.015385 23.630769-63.015385 63.015385s23.630769 63.015385 63.015385 63.015385h275.692308c259.938462 0 378.092308 7.876923 378.092307 252.061538s-118.153846 252.061538-378.092307 252.061539H315.076923c-31.507692 0-63.015385 23.630769-63.015385 63.015384s31.507692 55.138462 63.015385 55.138462h275.692308c228.430769 0 496.246154 0 496.246154-378.092308s-267.815385-370.215385-496.246154-370.215385zM47.261538 514.914462l259.938462-196.923077c39.384615-23.630769 86.646154-15.753846 110.276923 15.753846 7.876923 15.753846 15.753846 31.507692 15.753846 47.261538v393.846154c0 47.261538-31.507692 78.769231-78.769231 78.769231-15.753846 0-31.507692-7.876923-47.261538-15.753846l-259.938462-196.923077c-39.384615-31.507692-47.261538-78.769231-15.753846-110.276923 0-7.876923 7.876923-15.753846 15.753846-15.753846z" horiz-adv-x="1102" />

Before

Width:  |  Height:  |  Size: 410 KiB

After

Width:  |  Height:  |  Size: 410 KiB

@ -164,7 +164,7 @@ class Fileslists extends Component{
let list = response.data.course_modules;
let course_second_categoriess;
list.map((item, key) => {
course_second_categoriess = item.children
course_second_categoriess = item.children?item.children:[]
})
this.setState({
@ -460,11 +460,11 @@ class Fileslists extends Component{
addDir = () => {
let {filesId,course_modules,coursesecondcategoryid}=this.state;
//调用获取资源接口 刷新数据
//调用获取资源接口 刷新数据
this.setState({
checkBoxValues:[]
})
if(parseInt(this.props.match.params.main_id)!=parseInt(this.props.coursesids)){
trigger('attachmentAddlog', {id: parseInt( course_modules&&course_modules.course_modules[0].value),name:'资源',coursesecondcategoryid:coursesecondcategoryid})
@ -793,7 +793,7 @@ class Fileslists extends Component{
course_groupslist:id
})
}
render(){
let { searchValue,
@ -829,6 +829,7 @@ class Fileslists extends Component{
} = this.state;
let category_id= this.props.match.params.category_id;
// console.log(this.state.course_groups)
return(
<React.Fragment >
@ -1024,7 +1025,7 @@ class Fileslists extends Component{
</style>
<ul className="drop_down_menu" style={{"right":"0px","left":"unset","min-width":'180px'}}>
{/* <p style={{marginLeft:15,color:"#000000",fontSize:20}}>资源</p> */}
{this.state.course_second_categories.length>10? <p className="drop_down_search">
{this.state.course_second_categories&&this.state.course_second_categories.length>10? <p className="drop_down_search">
<Input placeholder="搜索" value={this.state.dirSearchValue} onChange={(e) => {this.setState({dirSearchValue: e.target.value})}}/>
</p>:""}
@ -1036,7 +1037,7 @@ class Fileslists extends Component{
{ course_modules&&course_modules.course_modules.map( (item,key) => {
return item.children.filter((item)=> {
return item.children&&item.children.filter((item)=> {
return (!this.state.dirSearchValue || item.name.indexOf(this.state.dirSearchValue) != -1)
}).map((itm,k)=>{
return(
@ -1044,13 +1045,13 @@ class Fileslists extends Component{
<div>
<div className="bordboom" style={{display:'flex',marginTop:15,height:30}}>
<div onClick={() => this.moveTos(itm.value )} style={{marginLeft:15,width:itm.title.length>13?200:undefined,color:'#000000',overflow: 'hidden',textOverflow:'ellipsis',whiteSpace: 'nowrap'}}>{itm.title}</div>
{itm.children.length===0?'':<i style={{marginLeft:15,marginRight:15}} onClick={() => this.istowshow(itm,filesId)} className="iconfont icon-xiajiantou font-12 ml2"></i>}
{itm.children.length===0?'':<i style={{marginLeft:15,marginRight:15}} onClick={() => this.istowshow(itm,filesId)} className="iconfont icon-xiajiantou font-12 ml2"></i>}
</div>
{ this.state.istowshowid===itm.value?
itm.children.map((tt,ti) => {
return(
filesId&&filesId===itm.id?"":
<div style={{marginLeft:30}} key={ti} id={tt.value} onClick={() => this.moveTos(tt.value )} title={tt.name}>{tt.title}</div>
<div style={{marginLeft:30}} key={ti} id={tt.value} onClick={() => this.moveTos(tt.value )} title={tt.name}>{tt.title}</div>
)
})
:''}
@ -1058,7 +1059,7 @@ class Fileslists extends Component{
)
})
})}
{this.state.course_second_categories.length===0?
{this.state.course_second_categories&&this.state.course_second_categories.length===0?
<div className={"courseSecond"}>暂无数据</div>:""}
{/*{course_modules&&course_modules.course_modules.map((item,key)=>{*/}

@ -268,7 +268,6 @@ class VideoIndex extends Component {
const newOperation = flag;
const new_upload = flag && (is_teacher && this.props.checkIfProfessionalCertification());
const isAdmin = this.props&& this.props.isAdmin();
return (
@ -333,7 +332,7 @@ class VideoIndex extends Component {
:
<WordsBtn style="blue" className="ml30 font-16 tongjis"
onClick={() => this.statisticsy(true)}
><i className="iconfont icon-tongji1 mr5"></i></WordsBtn>
><i className="iconfont icon-tongji1 mr5 font-14"></i></WordsBtn>
}
</span>
@ -378,12 +377,9 @@ class VideoIndex extends Component {
</div>
</div>
:
(
isAdmin?
<Videostatistics {...this.props} {...this.state} statisticsy={(b) => this.statisticsy(b)}></Videostatistics>
:
<Videostatisticscomtwo {...this.props} {...this.state} mytitle={""} ></Videostatisticscomtwo>
)
<Videostatistics {...this.props} {...this.state} statisticsy={(b) => this.statisticsy(b)}></Videostatistics>
}
{
statistics === false ?

@ -178,7 +178,6 @@
margin:0px auto;
}
.tongjis{
border: 1px solid #4CACFF;
padding-left: 10px;
padding-right: 10px;
padding-top: 5px;
@ -187,3 +186,6 @@
line-height: 1px;
}
.font-14{
font-size: 14px !important;
}

@ -213,17 +213,25 @@ class sendResources extends Component{
}
// console.log("description");
// console.log(description);
if(description===undefined||description===null){
if(description===undefined){
}else {
if(description.length>100){
this.setState({
descriptiontype:true
})
return
}
}else if(description.length>100){
this.setState({
descriptiontype:true
})
return
}
if(this.props.Exterchainname==="资源设置"){
//设置
let coursesId=this.props.match.params.coursesId;
@ -240,13 +248,17 @@ class sendResources extends Component{
description:description,
delay_publish:Radiovalue,
}).then((result)=>{
if(result.data.status===0){
this.ModalCancelModalCancel();
this.props.updataleftNavfun();
this.props.showNotification("设置资源成功");
this.props.setupdate(1,false)
}else{
this.props.showNotification(result.data.message);
if(result){
if(result.data){
if(result.data.status===0){
this.ModalCancelModalCancel();
this.props.updataleftNavfun();
this.props.showNotification("设置资源成功");
this.props.setupdate(1,false)
}else{
this.props.showNotification(result.data.message);
}
}
}
})
@ -266,22 +278,20 @@ class sendResources extends Component{
description:description,
delay_publish:Radiovalue,
}).then((result)=>{
if(result.data.status===0){
this.ModalCancelModalCancel();
this.props.updataleftNavfun();
this.props.showNotification("上传资源成功");
this.props.setupdate(1,false)
}else{
this.props.showNotification(result.data.message);
if(result){
if(result.data){
if(result.data.status===0){
this.ModalCancelModalCancel();
this.props.updataleftNavfun();
this.props.showNotification("上传资源成功");
this.props.setupdate(1,false)
}else{
this.props.showNotification(result.data.message);
}
}
}
})
}
}
settextarea=(e)=>{
@ -348,7 +358,7 @@ class sendResources extends Component{
}
handleChangess=(e)=>{
this.setState({
this.setState({
resourceurl:e.target.value,
resourceurlbool:false,
})

@ -38,6 +38,7 @@ class ShixunWorkReport extends Component {
work_comment_hidden:undefined,
work_comment:undefined,
has_commit: false,
shixun_detail:[]
}
}
@ -113,7 +114,8 @@ class ShixunWorkReport extends Component {
work_comment_hidden:result.data.work_comment_hidden,
work_comment:result.data.work_comment,
spinning: false,
has_commit: result.data.has_commit
has_commit: result.data.has_commit,
shixun_detail:result.data.shixun_detail
})
}
@ -305,7 +307,7 @@ class ShixunWorkReport extends Component {
}
render() {
let {data, showAppraiseModaltype, work_comment_hidden, work_comment, has_commit} = this.state;
let {data, showAppraiseModaltype, work_comment_hidden, work_comment, has_commit,shixun_detail} = this.state;
let category_id=data===undefined?"":data.category===null?"":data.category.category_id;
let homework_common_id=data===undefined?"":data.homework_common_id;
@ -313,7 +315,8 @@ class ShixunWorkReport extends Component {
const antIcon = <Icon type="loading" style={{ fontSize: 24 }} spin />;
// let showAppraiseModals=this.props&&this.props.isAdminOrTeacher()===true?work_comment===null||work_comment===undefined?false:true:work_comment===null||work_comment===undefined?false:true;
let showAppraiseModals=work_comment===null||work_comment===undefined?false:true;
// let showAppraiseModals=work_comment===null||work_comment===undefined?false:true;
// console.log(this.props.isAdmin())
document.title=data&&data.course_name;
return (
@ -454,7 +457,20 @@ class ShixunWorkReport extends Component {
<div className="stud-class-set">
<div className="clearfix edu-back-white poll_list">
<div className="font-16 color-dark-21 shixunreporttitleboxtop pd20">总体评价</div>
<div className="font-16 color-dark-21 shixunreporttitleboxtop pd20">
<div className={"fl"}>总体评价</div>
<div className={"fr"}>
{
this.props&&this.props.isAdmin()===true?shixun_detail&&shixun_detail.map((item,key)=>{
if(key===0){
return(
<a className={"color-blue font-16"} href={/tasks/+item.game_identifier} target="_blank" >查看学员实训</a>
)
}
}):""
}
</div>
</div>
<div className="font-16 color-dark-21 shixunreporttitleboxbom pd20">
<div style={{clear:"both",height:'100px'}}>

@ -66,9 +66,8 @@ class Detailss extends Component {
}}>
<div className="ws100s teacherentrydiv ">
<div className="ws100s sortinxdirection">
<p className="sortinxdirection" style={{color:'#5091FF'}} onClick={()=>this.props.qiandaoxiangq(false)}>
<i style={{color:'#5091FF'}} className="iconfont icon-zuojiantou posiivsiconmyss mr5 colorbluesigin xiaoshou" onClick={()=>this.props.qiandaoxiangq(false)}></i>
<p style={{color:'#5091FF'}} className="fh mr27 colorbluesigin xiaoshou" onClick={()=>this.props.qiandaoxiangq(false)}>返回</p>
<p className="sortinxdirection" onClick={()=>this.props.qiandaoxiangq(false)}>
<i style={{color:'#BBBBBB'}} className="iconfont icon-zuojiantou1 posiivsiconmyss mr5 colorbluesigin xiaoshou font-14" onClick={()=>this.props.qiandaoxiangq(false)}></i>
</p>
<p className="ws100s teachedivp ymaxnamewidthdivp86">
{item && item.name}

@ -108,6 +108,12 @@
.ws45s{
width: 45%;
}
.ws46s{
width: 46%;
}
.ws47s{
width: 47%;
}
.hs30s{
height: 30%;
}
@ -476,3 +482,9 @@
.mr27{
margin-right: 27px;
}
.pd15s{
padding-bottom: 15px !important;
}
.ml32{
margin-left: 32px;
}

@ -4,6 +4,8 @@ import '../signin/css/signincdi.css';
import Videostatisticscom from './component/Videostatisticscom';
import Videostatisticslist from './component/Videostatisticslist';
import Videostatisticscomtwo from './component/Videostatisticscomtwo';
import Studenticscom from './component/Studenticscom';
import Studentstatistics from './component/Studentstatistics';
//在线学习
@ -21,16 +23,23 @@ class Videostatistics extends Component{
}
componentDidMount() {
this.togetdatas();
const myisAdmin= this.props&& this.props.isAdmin();
if(myisAdmin===true){
this.togetdatas();
}else{
this.togetdataStudent();
}
}
details=()=>{
}
togetdatas(){
console.log("视频统计老师");
const CourseId=this.props.match.params.coursesId;
let url=`/courses/${CourseId}/watch_statics.json`;
axios.get(url).then((response) => {
axios.get(url,{params: {all:true}}).then((response) => {
if(response){
this.setState({
watch_staticsdata:response.data,
@ -44,6 +53,24 @@ class Videostatistics extends Component{
});
}
togetdataStudent(){
console.log("视频统计学生数据");
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,mytitle)=>{
this.setState({
tisticsbool:bool,
@ -55,6 +82,7 @@ class Videostatistics extends Component{
render(){
let {watch_staticsdata,tisticsbool,tisid,mytitle}= this.state;
const isAdmin = this.props&& this.props.isAdmin();
return(
<React.Fragment>
@ -64,13 +92,22 @@ class Videostatistics extends Component{
<div className="ws100s" style={{
position: "relative",
}}>
{
isAdmin?
<Videostatisticscom {...this.state} {...this.props} watch_staticsdata={watch_staticsdata} statisticsy={(b)=>this.props.statisticsy(b)}></Videostatisticscom>
:
<Studenticscom {...this.state} {...this.props} watch_staticsdata={watch_staticsdata} statisticsy={(b)=>this.props.statisticsy(b)}></Studenticscom>
<Videostatisticscom {...this.state} {...this.props} watch_staticsdata={watch_staticsdata} statisticsy={(b)=>this.props.statisticsy(b)}></Videostatisticscom>
}
<div>
<Videostatisticslist {...this.state} {...this.props} tisticsbools={(b,id,t)=>this.tisticsbools(b,id,t)}></Videostatisticslist>
{ isAdmin?
<Videostatisticslist {...this.state} {...this.props} tisticsbools={(b,id,t)=>this.tisticsbools(b,id,t)}></Videostatisticslist>
:
<Studentstatistics {...this.state} {...this.props} tisticsbools={(b,id,t)=>this.tisticsbools(b,id,t)}></Studentstatistics>
}
</div>

@ -0,0 +1,108 @@
import React, {Component} from "react";
import '../../signin/css/signincdi.css';
import {Progress, message} from 'antd';
import {getImageUrl} from 'educoder';
import axios from 'axios';
//条目
class Studenticscom extends Component {
//条目组件
constructor(props) {
super(props);
this.state = {}
}
componentDidMount() {
}
componentDidUpdate = (prevProps) => {
}
render() {
return (
<React.Fragment>
<div className="ws100s edu-back-white sortinxdirection" style={{
position: "relative"
}}>
<div className="ws100s teacherentrydivss ">
<div className="ws100s sortinxdirection">
<p className="sortinxdirection h40s" onClick={()=>this.props.statisticsy(false)} >
<i className="iconfont icon-zuojiantou1 font-14 posiivsiconmyss mr5 colorbluesigin xiaoshou h36s" style={{color:'#BBBBBB'}} onClick={()=>this.props.statisticsy(false)} ></i>
</p>
<div className="ws47s sptits font-18" style={{
color:"#333333"
}}><span className="ml10">视频统计总览</span></div>
<div className="ws50s sptitss xaxisreverseorder">播放数据从{this.props.watch_staticsdata&&this.props.watch_staticsdata.begin_at?this.props.watch_staticsdata.begin_at:0}开始统计</div>
</div>
<style>
{
`
.yslsprenshu{
background-image: url(${getImageUrl(`images/qiandao/studentbz1.png`)});
background-repeat:no-repeat;
-moz-background-size:100% 100%;
background-size:100% 100%;
}
.yslspcishu{
background-image: url(${getImageUrl(`images/qiandao/studentbz2.png`)});
background-repeat:no-repeat;
-moz-background-size:100% 100%;
background-size:100% 100%;
}
.yslshipingshi{
background-image: url(${getImageUrl(`images/qiandao/studentbz3.png`)});
background-repeat:no-repeat;
-moz-background-size:100% 100%;
background-size:100% 100%;
}
`
}
</style>
<div className="ws100s spacearound mt10">
<div className="yslsprenshu mr30" style={{width:260,height:100}}>
<div className="ws100s verticallayout tbrt">
<div className="ws100s ts">观看总次数</div>
<div className="ws100s tss">{this.props.watch_staticsdata&&this.props.watch_staticsdata.freq?this.props.watch_staticsdata.freq:0}</div>
</div>
</div>
<div className="yslspcishu mr30" style={{width:260,height:100}}>
<div className="ws100s verticallayout tbrt">
<div className="ws100s ts">观看总个数</div>
<div className="ws100s tss">{this.props.watch_staticsdata&&this.props.watch_staticsdata.num?this.props.watch_staticsdata.num:0}</div>
</div>
</div>
<div className="yslshipingshi" style={{width:260,height:100}}>
<div className="ws100s verticallayout tbrt">
<div className="ws100 ts">总观看时长</div>
<div className="ws100s tss">{this.props.watch_staticsdata&&this.props.watch_staticsdata.total_duration?this.props.watch_staticsdata.total_duration:0}</div>
</div>
</div>
</div>
</div>
</div>
</React.Fragment>
)
}
}
export default Studenticscom;

@ -0,0 +1,318 @@
import React, {Component} from "react";
import '../../signin/css/signincdi.css';
import {Pagination,Table,Spin} from 'antd';
import {getImageUrl,sortDirections,formatSeconds} from 'educoder';
import axios from 'axios';
import LoadingSpin from "../../../../common/LoadingSpin";
import NoneDatas from "../../signin/component/NoneDatas";
//条目
class Studentstatistics extends Component {
//条目组件
constructor(props) {
super(props);
this.state = {
columnsstu: [
{
title: '序号',
dataIndex: 'number',
key: 'number',
align: "center",
className: 'font-14',
width: '90px',
render: (text, record) => (
<span style={{width: '90px'}}>{record.number}</span>
),
},
{
title: '视频名称',
dataIndex: 'title',
key: 'title',
align: "center",
className: 'font-14 maxnamewidth150s',
width: '150px',
render: (text, record) => (
<span style={{width: '150px'}} className="maxnamewidth150s">
<a className="maxnamewidth150s" style={{
color:"#333333"
}} title={record.title}>{record.title}</a>
</span>
),
},
{
title: '观看次数(次)',
dataIndex: 'feq',
key: 'feq',
align: "center",
className: 'font-14',
width: '98px',
sorter: true,
sortDirections: sortDirections,
render: (text, record) => (
<span style={{width: '98px'}}>{record.feq}</span>
),
},
{
title: '观看时长',
dataIndex: 'total_duration',
key: 'total_duration',
align: "center",
className: 'font-14 maxnamewidth100s',
width: '100px',
sorter: true,
sortDirections: sortDirections,
render: (text, record) => (
<span style={{width: '100px'}} className="maxnamewidth100s">
<a className="maxnamewidth100s" style={{
color:"#333333"
}} title={record.total_duration}>{record.total_duration}</a>
</span>
),
},
{
title: '发布人',
dataIndex: 'user_name',
key: 'user_name',
align: "center",
className: 'font-14 maxnamewidth100s',
width: '100px',
render: (text, record) => (
<span style={{width: '100px'}} className="maxnamewidth100s">
<a className="maxnamewidth100s" style={{
color:"#333333"
}} title={record.user_name}>{record.user_name}</a>
</span>
),
},
{
title: '是否看完',
dataIndex: 'is_finished',
key: 'is_finished',
align: "center",
className: 'font-14',
width: '90px',
render: (text, record) => (
<span style={{width: '90px'}}>{record.is_finished === true ?
<span style={{color: "#5091FF"}}></span> : <span style={{color: "#E02020"}}></span>}</span>
),
},
],
loading:false,
data:[],
page:1,
limit:20,
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}/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),
title: response.data.data[i].title,
user_name: response.data.data[i].user_name,
is_finished: response.data.data[i].is_finished,
total_duration:response.data.data[i].total_duration?formatSeconds(response.data.data[i].total_duration):0,
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
})
});
}
//实训作业tbale 列表塞选数据
table1handleChange = (pagination, filters, sorter) => {
if (JSON.stringify(sorter) === "{}") {
//没有选择
} else {
try {
//学生学号排序
if (sorter.columnKey === "feq"||sorter.columnKey === "total_duration") {
let mysorder="";
if (sorter.order === "ascend") {
if(sorter.columnKey === "feq"){
mysorder="feq-asc";
}else{
mysorder="total_duration-asc";
}
//升序
let data={
page:this.state.page,
order:mysorder
}
this.togetdatas(data);
this.setState({
order: mysorder,
})
} else if (sorter.order === "descend") {
if(sorter.columnKey === "feq"){
mysorder="feq-desc";
}else{
mysorder="total_duration-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 (
<React.Fragment>
<div className="ws100s mt20">
<div className="ws100s edu-back-white">
<div className="ws100s teacherentrydivss pd15s">
<div className="ws100s sortinxdirection">
<div className="ws100s sptits font-18">统计列表</div>
</div>
</div>
<style>
{
`
.ysltableo .ant-table-thead > tr > th, .ant-table-tbody > tr > td {
padding: 10px 10px;
}
`
}
</style>
<div className="ws100s ysltableo teacherentrydivs pdinstop0" style={{ minHeight: "400px"}}>
{
data&&data.length===0?
<div style={{
minHeight: "400px",
}} className="ws100s">
<NoneDatas></NoneDatas>
</div>
: data&&data.length>0?
<Spin spinning={loading}>
<Table
columns={columnsstu}
dataSource={data}
pagination={false}
onChange={this.table1handleChange}
/>
</Spin>:
<div style={{
minHeight: "400px",
}} className="ws100s">
<NoneDatas></NoneDatas>
</div>
}
</div>
</div>
<div className="mb30 clearfix educontent mt40 intermediatecenter">
{
data&&data.length>0?
<Pagination showQuickJumper current={this.state.page} onChange={this.paginationonChange}
pageSize={this.state.limit}
total={this.state.members_count}></Pagination>
:""
}
</div>
</div>
</React.Fragment>
)
}
}
export default Studentstatistics;

@ -35,11 +35,12 @@ class Videostatisticscom extends Component {
}}>
<div className="ws100s teacherentrydivss ">
<div className="ws100s sortinxdirection">
<p className="sortinxdirection h40s" onClick={()=>this.props.statisticsy(false)} style={{color:'#5091FF'}}>
<i className="iconfont icon-zuojiantou posiivsiconmyss mr5 colorbluesigin xiaoshou h36s" onClick={()=>this.props.statisticsy(false)} style={{color:'#5091FF'}}></i>
{/*<p style={{color:'#5091FF'}} className="fh mr20 colorbluesigin xiaoshou h40s" onClick={()=>this.props.statisticsy(false)}>返回</p>*/}
<p className="sortinxdirection h40s" onClick={()=>this.props.statisticsy(false)} >
<i className="iconfont icon-zuojiantou1 font-14 posiivsiconmyss mr5 colorbluesigin xiaoshou h36s" style={{color:'#BBBBBB'}} onClick={()=>this.props.statisticsy(false)} ></i>
</p>
<div className="ws45s sptits font-18">视频统计总览</div>
<div className="ws47s sptits font-18" style={{
color:"#333333"
}}><span className="ml10">视频统计总览</span></div>
<div className="ws50s sptitss xaxisreverseorder">播放数据从{this.props.watch_staticsdata&&this.props.watch_staticsdata.begin_at?this.props.watch_staticsdata.begin_at:0}开始统计</div>
</div>
<style>
@ -68,16 +69,16 @@ class Videostatisticscom extends Component {
}
</style>
<div className="ws100s spacearound mt10">
<div className="yslsprenshu" style={{width:260,height:100}}>
<div className="yslsprenshu mr30" style={{width:260,height:100}}>
<div className="ws100s verticallayout tbrt">
<div className="ws100s ts">观看总人数</div>
<div className="ws100s tss">{this.props.watch_staticsdata&&this.props.watch_staticsdata.people_num?this.props.watch_staticsdata.people_num:0}</div>
<div className="ws100s tss">{this.props.watch_staticsdata&&this.props.watch_staticsdata.num?this.props.watch_staticsdata.num:0}</div>
</div>
</div>
<div className="yslspcishu" style={{width:260,height:100}}>
<div className="yslspcishu mr30" style={{width:260,height:100}}>
<div className="ws100s verticallayout tbrt">
<div className="ws100s ts">观看总人次</div>
<div className="ws100s tss">{this.props.watch_staticsdata&&this.props.watch_staticsdata.freq?this.props.watch_staticsdata.freq:0}</div>

@ -485,7 +485,7 @@ class Videostatisticscomtwo extends Component {
}}>
{
isAdmin === true ?
<div className="xiaoshou" onClick={() => this.props.tisticsbools(false, null)}>
<div className="xiaoshou ml32" onClick={() => this.props.tisticsbools(false, null)}>
<span className="mr5 xiaoshou">视频统计总览</span><i className="iconfont icon-fanhui font-13 xiaoshou"></i>
</div>
:""
@ -495,14 +495,14 @@ class Videostatisticscomtwo extends Component {
isAdmin === true ?
<div className="xiaoshou" onClick={() => this.fenbanone()}>
<Dropdown getPopupContainer={trigger => trigger.parentNode} overlay={menu}
placement="bottomCenter">
placement="bottomLeft">
<span>
<span className="mr5 xiaoshou">分班</span>
{
fbbool === true ?
<i className="iconfont icon-sanjiaoxing-up font-13 mr32 xiaoshou"></i>
<i className="iconfont icon-sanjiaoxing-up font-13 xiaoshou"></i>
:
<i className="iconfont icon-sanjiaoxing-down font-13 mr32 xiaoshou"></i>
<i className="iconfont icon-sanjiaoxing-down font-13 xiaoshou"></i>
}
</span>
</Dropdown>

@ -250,9 +250,9 @@ class Videostatisticslist extends Component {
<React.Fragment>
<div className="ws100s mt20">
<div className="ws100s edu-back-white">
<div className="ws100s teacherentrydivss ">
<div className="ws100s teacherentrydivss pd15s">
<div className="ws100s sortinxdirection">
<div className="ws100s sptits font-16">统计列表</div>
<div className="ws100s sptits font-18">统计列表</div>
</div>
</div>
@ -268,13 +268,13 @@ class Videostatisticslist extends Component {
<div className="ws100s ysltableo teacherentrydivs pdinstop0" style={{ minHeight: "400px"}}>
{
data.length===0?
data&&data.length===0?
<div style={{
minHeight: "400px",
}} className="ws100s">
<NoneDatas></NoneDatas>
</div>
:
: data&&data.length>0?
<Spin spinning={loading}>
<Table
columns={columnsstu}
@ -284,6 +284,12 @@ class Videostatisticslist extends Component {
/>
</Spin>
:
<div style={{
minHeight: "400px",
}} className="ws100s">
<NoneDatas></NoneDatas>
</div>
}

@ -30,6 +30,12 @@
<div class="content unicode" style="display: block;">
<ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont">&#xe73a;</span>
<div class="name">返回左键头</div>
<div class="code-name">&amp;#xe73a;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe739;</span>
<div class="name">返回</div>
@ -2090,6 +2096,15 @@
<div class="content font-class">
<ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont icon-zuojiantou1"></span>
<div class="name">
返回左键头
</div>
<div class="code-name">.icon-zuojiantou1
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-fanhui"></span>
<div class="name">
@ -5134,6 +5149,14 @@
<div class="content symbol">
<ul class="icon_lists dib-box">
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-zuojiantou1"></use>
</svg>
<div class="name">返回左键头</div>
<div class="code-name">#icon-zuojiantou1</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-fanhui"></use>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -5,6 +5,13 @@
"css_prefix_text": "icon-",
"description": "",
"glyphs": [
{
"icon_id": "13511742",
"name": "返回左键头",
"font_class": "zuojiantou1",
"unicode": "e73a",
"unicode_decimal": 59194
},
{
"icon_id": "13458315",
"name": "返回",

@ -20,6 +20,9 @@ Created by iconfont
/>
<missing-glyph />
<glyph glyph-name="zuojiantou1" unicode="&#59194;" d="M832.503909-127.983381a63.919062 63.919062 0 0 0-38.990629 12.144622L151.765893 340.543347a51.13525 51.13525 0 0 0 0 85.651544l639.190625 457.021297a67.754206 67.754206 0 0 0 87.569116-8.309479 50.496059 50.496059 0 0 0-9.58786-77.342065L289.831068 383.369119l581.663469-412.277953a50.496059 50.496059 0 0 0 9.587859-77.342066 63.919062 63.919062 0 0 0-48.578487-21.732481z" horiz-adv-x="1024" />
<glyph glyph-name="fanhui" unicode="&#59193;" d="M590.769231-107.362462H315.076923c-31.507692 0-63.015385 23.630769-63.015385 63.015385s23.630769 63.015385 63.015385 63.015385h275.692308c259.938462 0 378.092308 7.876923 378.092307 252.061538s-118.153846 252.061538-378.092307 252.061539H315.076923c-31.507692 0-63.015385 23.630769-63.015385 63.015384s31.507692 55.138462 63.015385 55.138462h275.692308c228.430769 0 496.246154 0 496.246154-378.092308s-267.815385-370.215385-496.246154-370.215385zM47.261538 514.914462l259.938462-196.923077c39.384615-23.630769 86.646154-15.753846 110.276923 15.753846 7.876923 15.753846 15.753846 31.507692 15.753846 47.261538v393.846154c0 47.261538-31.507692 78.769231-78.769231 78.769231-15.753846 0-31.507692-7.876923-47.261538-15.753846l-259.938462-196.923077c-39.384615-31.507692-47.261538-78.769231-15.753846-110.276923 0-7.876923 7.876923-15.753846 15.753846-15.753846z" horiz-adv-x="1102" />

Before

Width:  |  Height:  |  Size: 410 KiB

After

Width:  |  Height:  |  Size: 410 KiB

Loading…
Cancel
Save