Merge branch 'dev_aliyun' of http://bdgit.educoder.net/Hjqreturn/educoder into dev_aliyun

courseware
cxt 5 years ago
commit 4f6ce50dc0

@ -0,0 +1,17 @@
class Admins::SchoolBaseStatisticsController < Admins::BaseController
def index
params[:sort_by] = params[:sort_by].presence || :teacher_count
params[:sort_direction] = params[:sort_direction].presence || :desc
total_count, statistics = Admins::SchoolBaseStatisticService.call(params)
@statistics = paginate statistics, total_count: total_count
@params_page = params[:page] || 1
respond_to do |format|
format.html
format.js
end
end
end

@ -0,0 +1,138 @@
class Admins::SchoolBaseStatisticService < ApplicationService
include CustomSortable
attr_reader :params
sort_columns :student_count, :teacher_count, :course_count, :course_group_count,
:attachment_count, :video_count, :normal_work_count, :shixun_work_count, :evaluate_count,
:student_work_count, :exercise_count, default_direction: :desc
def initialize(params)
@params = params
end
def call
schools = School.group('schools.id')
keyword = params[:keyword].try(:to_s).try(:strip)
if keyword.present?
schools = schools.where("schools.name LIKE :keyword OR schools.id LIKE :keyword", keyword: "%#{keyword}%")
end
count = schools.count.count
# 根据排序字段进行查询
schools = query_by_sort_column(schools, params[:sort_by])
schools.reorder("#{ params[:sort_by] != 0} desc")
schools = custom_sort(schools, params[:sort_by], params[:sort_direction])
schools = schools.limit(page_size).offset(offset)
schools = package_other_data(schools)
[count, schools]
end
def package_other_data(schools)
ids = schools.map(&:id)
student_count = CourseMember.course_students.joins(course: :school).group(:school_id).where("role= 'STUDENT' AND courses.is_delete = false AND schools.id in (?)", ids).count("distinct user_id")
teachers = UserExtension.where(school_id: ids, identity: :teacher).group(:school_id)
teacher_count = teachers.count
courses = Course.where(is_delete: 0, school_id: ids).group(:school_id)
course_count= courses.count
course_group_count = courses.joins(:course_groups).count
attachment_count = courses.joins(:attachments).count
video_count = teachers.joins(user: :videos).where("videos.delete_state IS NOT NULL").count
homeworks = HomeworkCommon.joins(:course).where(courses: { school_id: ids }).where("courses.is_delete = false")
shixun_work_count = homeworks.where(homework_type: 4).group(:school_id).count
normal_work_count = homeworks.where(homework_type: 1).group(:school_id).count
student_work_count = homeworks.joins(:student_works).group(:school_id).count
evaluate_count = EvaluateRecord.unscoped.joins('JOIN homework_commons_shixuns hcs ON hcs.shixun_id = evaluate_records.shixun_id
JOIN homework_commons hc ON hcs.homework_common_id = hc.id AND hc.homework_type = 4
JOIN course_members ON course_members.user_id = evaluate_records.user_id
JOIN courses ON course_members.course_id = courses.id AND hc.course_id = courses.id')
.where(courses: { school_id: ids })
.group(:school_id).count
exercise_count = Exercise.joins(:course).where(courses: { school_id: ids }).group(:school_id).count
schools.map do |school|
{
id: school.id,
name: school.name,
teacher_count: teacher_count[school.id],
student_count: student_count[school.id],
course_count: course_count[school.id],
course_group_count: course_group_count[school.id],
attachment_count: attachment_count[school.id],
video_count: video_count[school.id],
normal_work_count: normal_work_count[school.id],
shixun_work_count: shixun_work_count[school.id],
student_work_count: student_work_count[school.id],
evaluate_count: evaluate_count[school.id],
exercise_count: exercise_count[school.id]
}
end
end
private
def query_by_sort_column(schools, sort_by_column)
base_query_column = 'schools.id, schools.name'
case sort_by_column.to_s
when 'teacher_count' then
schools.joins('LEFT JOIN user_extensions ue ON ue.school_id = schools.id AND ue.identity = 0')
.select("#{base_query_column}, COUNT(*) teacher_count")
when 'student_count' then
schools.joins("LEFT JOIN courses ue ON ue.school_id = schools.id AND ue.is_delete = FALSE
LEFT JOIN course_members ON course_members.course_id = ue.id AND course_members.role = 'STUDENT'")
.select("#{base_query_column}, COUNT(distinct user_id) student_count")
when 'course_count' then
schools.joins('LEFT JOIN courses ON courses.school_id = schools.id AND courses.is_delete = false')
.select("#{base_query_column}, COUNT(*) course_count")
when 'course_group_count' then
schools.joins("LEFT JOIN courses ON courses.school_id = schools.id AND courses.is_delete = false
LEFT JOIN course_groups ON course_groups.course_id = courses.id")
.select("#{base_query_column}, COUNT(*) course_group_count")
when 'attachment_count' then
schools.joins("LEFT JOIN courses cs ON cs.school_id = schools.id AND cs.is_delete = 0
LEFT JOIN attachments ON attachments.container_type ='Course' AND attachments.container_id = cs.id")
.select("#{base_query_column}, COUNT(*) attachment_count")
when 'video_count' then
schools.joins("LEFT JOIN user_extensions ue ON ue.school_id = schools.id AND ue.identity = 0
LEFT JOIN videos ON videos.user_id = ue.user_id AND videos.delete_state IS NOT NULL")
.select("#{base_query_column}, COUNT(*) video_count")
when 'normal_work_count' then
schools.joins("LEFT JOIN courses ON courses.school_id = schools.id
LEFT JOIN homework_commons ON homework_commons.course_id = courses.id AND homework_commons.homework_type = 0")
.select("#{base_query_column}, COUNT(*) normal_work_count")
when 'shixun_work_count' then
schools.joins("LEFT JOIN courses ON courses.school_id = schools.id
LEFT JOIN homework_commons ON homework_commons.course_id = courses.id AND homework_commons.homework_type = 4")
.select("#{base_query_column}, COUNT(*) shixun_work_count")
when 'student_work_count' then
schools.joins("LEFT JOIN courses ON courses.school_id = schools.id
LEFT JOIN homework_commons ON homework_commons.course_id = courses.id
LEFT JOIN student_works ON student_works.homework_common_id = homework_commons.id")
.select("#{base_query_column}, COUNT(*) student_work_count")
when 'evaluate_count' then
schools.joins('
LEFT JOIN courses ON courses.school_id = schools.id AND courses.is_delete = false
LEFT JOIN course_members ON course_members.course_id = courses.id
LEFT JOIN evaluate_records ON course_members.user_id = evaluate_records.user_id
LEFT JOIN homework_commons_shixuns hcs ON hcs.shixun_id = evaluate_records.shixun_id
LEFT JOIN homework_commons hc ON hcs.homework_common_id = hc.id AND hc.homework_type = 4')
.select("#{base_query_column}, COUNT(*) evaluate_count")
when 'exercise_count' then
schools.joins('LEFT JOIN courses cs ON cs.school_id = schools.id AND cs.is_delete = 0
LEFT JOIN exercises ON exercises.course_id = cs.id')
.select("#{base_query_column}, COUNT(*) exercise_count")
end
end
def page_size
params[:per_page] || 20
end
def offset
(params[:page].to_i.zero? ? 0 : params[:page].to_i - 1) * page_size
end
end

@ -2,6 +2,9 @@
<% add_admin_breadcrumb('概览', admins_path) %>
<% end %>
<% content_for(:head) do %>
<meta name="turbolinks-cache-control" content="no-cache">
<% end %>
<div class="header bg-gradient-primary pb-8 pt-md-8">
<div class="container-fluid">
<div class="header-body">

@ -0,0 +1,48 @@
<table class="table table-hover text-center school-base-statistic-list-table">
<thead class="thead-light">
<tr>
<th width="4%">序号</th>
<th width="10%" class="text-left">单位名称</th>
<th width="8%"><%= sort_tag('注册教师', name: 'teacher_count', path: admins_school_base_statistics_path) %></th>
<th width="8%"><%= sort_tag('注册学生', name: 'student_count', path: admins_school_base_statistics_path) %></th>
<th width="8%"><%= sort_tag('教学课堂', name: 'course_count', path: admins_school_base_statistics_path) %></th>
<th width="8%"><%= sort_tag('管理分班', name: 'course_group_count', path: admins_school_base_statistics_path) %></th>
<th width="8%"><%= sort_tag('课件资源', name: 'attachment_count', path: admins_school_base_statistics_path) %></th>
<th width="8%"><%= sort_tag('教学视频', name: 'video_count', path: admins_school_base_statistics_path) %></th>
<th width="8%"><%= sort_tag('普通作业', name: 'normal_work_count', path: admins_school_base_statistics_path) %></th>
<th width="8%"><%= sort_tag('实训作业', name: 'shixun_work_count', path: admins_school_base_statistics_path) %></th>
<th width="8%"><%= sort_tag('作业文件', name: 'student_work_count', path: admins_school_base_statistics_path) %></th>
<th width="8%"><%= sort_tag('评测次数', name: 'evaluate_count', path: admins_school_base_statistics_path) %></th>
<th width="8%"><%= sort_tag('在线试卷', name: 'exercise_count', path: admins_school_base_statistics_path) %></th>
</tr>
</thead>
<tbody>
<% if statistics.present? %>
<% statistics.each_with_index do |statistic, index| %>
<tr>
<td><%= list_index_no(@params_page.to_i, index) %></td>
<td class="text-left">
<%= link_to statistic[:name], "/colleges/#{statistic[:id]}/statistics",
target: '_blank', data: { toggle: 'tooltip', title: '点击查看学校统计概况' } %>
</td>
<td><%= statistic[:teacher_count].to_i %></td>
<td><%= statistic[:student_count].to_i %></td>
<td><%= statistic[:course_count].to_i %></td>
<td><%= statistic[:course_group_count].to_i %></td>
<td><%= statistic[:attachment_count].to_i %></td>
<td><%= statistic[:video_count].to_i %></td>
<td><%= statistic[:normal_work_count].to_i %></td>
<td><%= statistic[:shixun_work_count].to_i %></td>
<td><%= statistic[:student_work_count].to_i %></td>
<td><%= statistic[:evaluate_count].to_i %></td>
<td><%= statistic[:exercise_count].to_i %></td>
</tr>
<% end %>
<% else %>
<%= render 'admins/shared/no_data_for_table' %>
<% end %>
</tbody>
</table>
<%= render partial: 'admins/shared/paginate', locals: { objects: statistics } %>

@ -0,0 +1,14 @@
<% define_admin_breadcrumbs do %>
<% add_admin_breadcrumb('数据项列表', admins_school_base_statistics_path) %>
<% end %>
<div class="box search-form-container school-base-statistic-list-form">
<%= form_tag(admins_school_base_statistics_path, method: :get, class: 'form-inline search-form', remote: true) do %>
<%= text_field_tag(:keyword, params[:keyword], class: 'form-control col-sm-2 ml-3', placeholder: '学校名称搜索') %>
<%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %>
<% end %>
</div>
<div class="box admin-list-container school-base-statistic-list-container">
<%= render partial: 'admins/school_base_statistics/list', locals: { statistics: @statistics } %>
</div>

@ -0,0 +1 @@
$(".school-base-statistic-list-container").html("<%= j(render partial: 'admins/school_base_statistics/list', locals: { statistics: @statistics }) %>")

@ -17,7 +17,8 @@
<li>
<%= sidebar_item_group('#school-submenu', '学校统计', icon: 'area-chart') do %>
<li><%= sidebar_item(admins_daily_school_statistics_path, '统计总表', icon: 'bar-chart', controller: 'admins-daily_school_statistics') %></li>
<li><%= sidebar_item(admins_school_statistics_path, '数据变化报表', icon: 'line-chart', controller: 'admins-schools') %></li>
<li><%= sidebar_item(admins_school_statistics_path, '数据变化报表', icon: 'line-chart', controller: 'admins-school_statistics') %></li>
<li><%= sidebar_item(admins_school_base_statistics_path, '数据项列表', icon: 'eyedropper', controller: 'admins-school_base_statistics') %></li>
<% end %>
</li>

@ -5,7 +5,7 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel='shortcut icon' type='image/x-icon' href='/favicon.ico' />
<%= yield :head %>
<%= csrf_meta_tags %>
<%= csp_meta_tag %>

@ -1173,6 +1173,8 @@ Rails.application.routes.draw do
get :contrast, on: :collection
end
resources :school_base_statistics, only: [:index]
resources :users, only: [:index, :edit, :update, :destroy] do
member do
post :reward_grade

@ -46,7 +46,7 @@ debugType = "admin";
// 老师
// debugType="teacher";
// 学生
// debugType="student";
//debugType="student";

@ -133,13 +133,15 @@ class TPIContextProvider extends Component {
})
}
componentWillMount () {
// 拦截判断是否离开当前页面
}
componentWillUnmount() {
this.costTimeInterval && window.clearInterval(this.costTimeInterval)
}
componentDidMount() {
window.$(window).unload( ()=>{
console.log(12321)
});
// TODO 登录状态的判断?
// request
@ -161,12 +163,15 @@ class TPIContextProvider extends Component {
}
}, 1000)
// 页面离开时存下用户的任务耗时
window.$(window).bind('beforeunload', function (e) {
console.log(111111)
// // 页面离开时存下用户的任务耗时
window.$(window).bind('beforeunload',()=>{
this._updateCostTime();
})
// window.$(window).unload( ()=>{
// this._updateCostTime();
// });
// // 页面离开时存下用户的任务耗时
// window.$(window).unload( ()=>{
// this._updateCostTime();

@ -24,7 +24,7 @@ class LiveItem extends Component{
visible:false
}
}
deleteLive=(id)=>{
this.props.confirm({
content: '是否确认删除?',
@ -136,7 +136,7 @@ class LiveItem extends Component{
item.url ?
<React.Fragment>
{
wei_flag ?
wei_flag ?
<a className="btns going" onClick={this.alertInfo}>进入</a>
:
<a className="btns going" target="_blank" href={`${item.url}`}>进入</a>
@ -154,17 +154,17 @@ class LiveItem extends Component{
<span className="lineMiddle color-grey-9">
<img alt={`${item.author_name}`} className="liveAuthor" src={getImageUrl(`images/${item.author_img}`)}/>
<label className="mr50">{item.author_name}</label>
{ item.platform && <span className="mr50">直播平台{item.platform}</span> }
{ item.live_time && <span className="mr50">开播时间{item.live_time}</span>}
{ item.platform && <span className="mr50">直播平台{item.platform}</span> }
{ item.live_time && <span className="mr50">开播时间{item.live_time}</span>}
{ item.duration && <span className="mr50">直播预计时长{item.duration}分钟</span> }
</span>
<span className="edu-txt-right" style={{width:"80px"}}>
<span className="edu-txt-right" style={{width:"120px"}}>
{
item.op_auth ?
<WordsBtn style="grey" onClick={()=>setLiveId(item.id)}>编辑</WordsBtn>:""
}
{
item.delete_auth ?
item.delete_auth ?
<WordsBtn style="grey" className="ml30" onClick={()=>this.deleteLive(item.id)}>删除</WordsBtn>
:""
}

@ -404,7 +404,7 @@ class CoursesBanner extends Component {
exitclass=()=>{
this.setState({
modalsType: true,
modalsTopval: "退出后您将不再是本课题的成员,作品将全部被删除,",
modalsTopval: "退出后您将不再是本课堂的成员,作品将全部被删除,",
modalsBottomval:"确定要退出该课堂吗?",
metype:6
})
@ -601,29 +601,41 @@ class CoursesBanner extends Component {
</div>
<div>
<a href={"/users/" + coursedata.teacher_login} className="fl">
<img alt="头像" className="radius fl mt3 bannerimgname"
src={getImageUrl(`images/` + coursedata.teacher_img)}/>
</a>
<div className="fl mt13">
<p className="color-white">
<a href={"/users/" + coursedata.teacher_login}
className="color-white bannnerusername">{coursedata.teacher_name}</a>
</p>
</div>
<div className="fl mt13">
<p className="color-white bannnerusernames">{coursedata.teacher_school}</p>
</div>
<div className="clearfix ">
<div className="fl fl mr40 mb20">
<a href={"/users/" + coursedata.teacher_login} className="fl">
<img alt="头像" className="radius fl mt3 bannerimgname"
src={getImageUrl(`images/` + coursedata.teacher_img)}/>
</a>
<div className="fl mt13">
<p className="color-white">
<a href={"/users/" + coursedata.teacher_login}
className="color-white bannnerusername">{coursedata.teacher_name}</a>
</p>
</div>
</div>
<div className="fl mt13">
<p className="color-white bannnerusernames">{coursedata.teacher_school}</p>
</div>
<div className="clearfix ">
<div className="fl fl mr40" >
<div className="task-hide" style={{height:25,marginBottom:10,marginLeft:60}}>
{coursedata.teacher_users.length===0?'':
<span className="color-white" >协作老师
{coursedata.teacher_users.map((iem,idx)=>{
return(
<span className="task-hide" style={{width:50,marginLeft:5}}>{idx<3?iem:''} {coursedata.teacher_users.length>3&&idx===2?'...':''} </span>
)
})
}
</span>
}
</div>
</div>
{/*{excellent===false?*/}
{/* :*/}
@ -753,12 +765,12 @@ background:rgba(204,204,204,0.2) !important;
placement="topLeft"
title={<pre className="antsoancss">
{coursedata.teacher_applies_count===undefined?"":coursedata.teacher_applies_count>0?
<span >您有{coursedata.teacher_applies_count}新的加入申请
<a className={"daishenp"} onClick={excellent === true && this.props.isAdminOrStudent() === false ?"":()=>this.setHistoryFun("/classrooms/"+this.props.match.params.coursesId+"/teachers?tab=2")}>
<span>新收到{coursedata.teacher_applies_count}加入课堂的申请
<a className={"daishenp ml5"} onClick={excellent === true && this.props.isAdminOrStudent() === false ?"":()=>this.setHistoryFun("/classrooms/"+this.props.match.params.coursesId+"/teachers?tab=2")}>
<span style={{
color:"#FFA804"
}}>
审批
审批
</span></a></span>:""}</pre>}>
<span className="color-grey-c font-16" onClick={excellent === true && this.props.isAdminOrStudent() === false ?"":()=>this.setHistoryFun("/classrooms/"+this.props.match.params.coursesId+"/teachers")}>
<span className={"mr10"}>教师</span>

@ -305,7 +305,7 @@ class ShixunhomeWorkItem extends Component{
<div className="clearfix ds pr contentSection" >
<style>{`
.maxwidth333{
max-width: 333px;
max-width: 300px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
@ -378,7 +378,7 @@ class ShixunhomeWorkItem extends Component{
}
{this.props.isAdminOrCreator()?<a onClick={(event)=>this.editname(discussMessage.name,discussMessage.homework_id,event)} className={"ml20 btn colorblue font-16 fontweight400 "}>重命名</a>:""}
{this.props.isAdmin()?<a onClick={(event)=>this.editname(discussMessage.name,discussMessage.homework_id,event)} className={"ml20 btn colorblue font-16 fontweight400 "}>重命名</a>:""}
{/*<WordsBtn className="btn colorblue ml20 font-16" to={`/classrooms/${this.props.match.params.coursesId}/${this.state.shixuntypes}/${discussMessage.homework_id}/settings?tab=3`} > 设置</WordsBtn>*/}
<WordsBtn className="btn colorblue font-16 ml15 fontweight400 " to={`/classrooms/${this.props.match.params.coursesId}/${this.state.shixuntypes}/${discussMessage.homework_id}/settings?tab=3`} > 设置</WordsBtn>
</span>:""}

@ -1188,7 +1188,7 @@ class ShixunHomework extends Component{
</span>}
</span>
<li className="fr">
{datas===undefined?"":datas.homeworks && datas.homeworks.length>1?this.props.isAdminOrCreator()===true?datas&&datas.category_name===undefined||datas&&datas.category_name===null?
{datas===undefined?"":datas.homeworks && datas.homeworks.length>1?this.props.isAdmin()===true?datas&&datas.category_name===undefined||datas&&datas.category_name===null?
<span>
<WordsBtn style="blue" className={"mr30 font-16"}>
<Link className="color4CACFF" to={`/classrooms/${this.props.match.params.coursesId}/ordering/shixun_homework/${main_id&&main_id}`}>调整排序</Link>

@ -1,9 +1,7 @@
import React, {Component} from "react";
import {WordsBtn} from 'educoder';
import {Table, InputNumber, Tooltip} from "antd";
import {Link, Switch, Route, Redirect} from 'react-router-dom';
import {Table, InputNumber, Tooltip,Badge} from "antd";
import axios from 'axios';
import './Shixunbage.css';
class OfficialAcademicTranscript extends Component {
constructor(props) {
@ -116,14 +114,15 @@ class OfficialAcademicTranscript extends Component {
className: "TaskForms",
render: (text, record) => (
<span>
<span className={"task-hide linhe15"} style={{color: "#676767"}}><a className="tasknameName font-14"
onClick={() => this.myjumptopic("id" + record.customs)}
title={record.taskname.name.length > 15 ? record.taskname.name : ""}>
{record.taskname.name}
</a>
{record.taskname.complete_status === 2 ?
<span className={"tasknamebox ml10"}>延时</span> : record.taskname.complete_status === 3 ?
<span className={"tasknameboxs ml10"}>延时</span> : ""}
<span className={"task-hide"} style={{color: "#676767"}}>
<a className="relative font-14" onClick={() => this.myjumptopic("id" + record.customs)}
title={record.taskname.name.length > 15 ? record.taskname.name : ""}>
<span className={"tasknameName fl mr5"}>{record.taskname.name}</span>
{record.taskname.complete_status === 2 ?
<Badge count={"延时"} className="site-badge-red fl pdt3" /> : record.taskname.complete_status === 3 ?
<Badge count={"无效"} className="site-badge-white fl pdt3" />: ""}
</a>
</span>
</span>
),
@ -305,10 +304,11 @@ class OfficialAcademicTranscript extends Component {
.tasknameName:link{color:#676767}
.tasknameName:hover{color:#4CACFF}
.tasknameName{
overflow: hidden;
display: inline-block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 225px;
max-width: 200px;
text-align: left !important;
}
.TaskForms{
@ -331,6 +331,9 @@ class OfficialAcademicTranscript extends Component {
.mr22{
margin-right: 22px;
}
.pdt3{
padding-top:3px;
}
`}
</style>
{datas === undefined ? "" : <Table

@ -0,0 +1,15 @@
.site-badge-red .ant-badge-count {
background-color: #FC2B6A;
color: #fff;
/*box-shadow: 0 0 0 1px #d9d9d9 inset;*/
}
.site-badge-white .ant-badge-count {
background-color: #EDEDED;
color: #666666;
/*box-shadow: 0 0 0 1px #d9d9d9 inset;*/
}
.relative{
position: relative;
}

@ -1372,14 +1372,14 @@ class TPMBanner extends Component {
{this.props.identity < 8 && shixunsDetails.shixun_status != -1 && shixunsDetails.shixun_status != 0?
<div className="fr kaike kkbth mr20 width155"
<div className="fr kaike kkbth mr20"
style={{display: shixunsDetails.can_copy === false || shixunsDetails.can_copy === null ? "none" : "flex"}}>
<Tooltip placement="bottom" title={"基于这个实训修改形成新的实训"}>
<span className="flex1 edu-txt-center fl font-18"
onClick={this.copyForkvisible}
style={{display: shixunsDetails.can_copy === false || shixunsDetails.can_copy === null ? "none" : "inline-block"}}
>
复制实训
复制
</span>
</Tooltip>

Loading…
Cancel
Save