Merge branches 'PCqiandao' and 'dev_aliyun' of https://bdgit.educoder.net/Hjqreturn/educoder into dev_aliyun

PCqiandao
杨树明 5 years ago
commit dce2471a5b

3
.gitignore vendored

@ -7,6 +7,7 @@
# Ignore bundler config. # Ignore bundler config.
/.bundle /.bundle
/bundle /bundle
/node_modules
# Ignore lock config file # Ignore lock config file
*.lock *.lock
@ -46,6 +47,8 @@
/public/h5build /public/h5build
/public/npm-debug.log /public/npm-debug.log
/dist
# avatars # avatars
/public/images/avatars /public/images/avatars

@ -8,23 +8,35 @@ class AttendancesController < ApplicationController
current_date = Date.current current_date = Date.current
current_end_time = Time.current.strftime("%H:%M:%S") current_end_time = Time.current.strftime("%H:%M:%S")
member = @course.students.find_by(user_id: current_user.id)
if params[:history] if params[:history]
if @user_course_identity == Course::STUDENT
history_attendance_ids = member.course_member_attendances.where(course_id: @course.id).pluck(:course_attendance_id)
@attendances = @course.course_attendances.where(id: history_attendance_ids.uniq).
where("attendance_date < '#{current_date}' or (attendance_date = '#{current_date}' and end_time < '#{current_end_time}')")
else
@attendances = @course.course_attendances.where("attendance_date < '#{current_date}' or @attendances = @course.course_attendances.where("attendance_date < '#{current_date}' or
(attendance_date = '#{current_date}' and end_time < '#{current_end_time}')") (attendance_date = '#{current_date}' and end_time < '#{current_end_time}')")
end
else
@attendances = @course.course_attendances.where("attendance_date > '#{current_date}' or
(attendance_date = '#{current_date}' and end_time > '#{current_end_time}')")
end
if @user_course_identity == Course::STUDENT if @user_course_identity == Course::STUDENT
member = @course.students.find_by(user_id: current_user.id)
group_ids = [member&.course_group_id.to_i, 0] group_ids = [member&.course_group_id.to_i, 0]
@attendances = @attendances.joins(:course_attendance_groups).where(course_attendance_groups: {course_group_id: group_ids}) @attendances = @attendances.joins(:course_attendance_groups).where(course_attendance_groups: {course_group_id: group_ids})
if params[:history]
attendance_ids = @attendances.pluck(:id) attendance_ids = @attendances.pluck(:id)
@normal_count = @course.course_member_attendances.where(course_member_id: member&.id, course_attendance_id: attendance_ids, attendance_status: "NORMAL").size @normal_count = @course.course_member_attendances.where(course_member_id: member&.id, course_attendance_id: attendance_ids, attendance_status: "NORMAL").size
@leave_count = @course.course_member_attendances.where(course_member_id: member&.id, course_attendance_id: attendance_ids, attendance_status: "LEAVE").size @leave_count = @course.course_member_attendances.where(course_member_id: member&.id, course_attendance_id: attendance_ids, attendance_status: "LEAVE").size
@absence_count = @course.course_member_attendances.where(course_member_id: member&.id, course_attendance_id: attendance_ids, attendance_status: "ABSENCE").size @absence_count = @course.course_member_attendances.where(course_member_id: member&.id, course_attendance_id: attendance_ids, attendance_status: "ABSENCE").size
end end
else
@attendances = @course.course_attendances.where("attendance_date > '#{current_date}' or
(attendance_date = '#{current_date}' and end_time > '#{current_end_time}')")
end end
@attendances_count = @attendances.size @attendances_count = @attendances.size
@attendances = @attendances.order("attendance_date desc, start_time desc") @attendances = @attendances.order("attendance_date desc, start_time desc")

@ -30,7 +30,7 @@ class CoursesController < ApplicationController
:informs, :update_informs, :online_learning, :update_task_position, :tasks_list, :informs, :update_informs, :online_learning, :update_task_position, :tasks_list,
:join_excellent_course, :export_couser_info, :export_member_act_score, :new_informs, :join_excellent_course, :export_couser_info, :export_member_act_score, :new_informs,
:delete_informs, :change_member_role, :course_groups, :join_course_group, :statistics, :delete_informs, :change_member_role, :course_groups, :join_course_group, :statistics,
:work_score, :act_score, :calculate_all_shixun_scores, :move_to_category] :work_score, :act_score, :calculate_all_shixun_scores, :move_to_category, :watch_video_histories]
before_action :user_course_identity, except: [:join_excellent_course, :index, :create, :new, :apply_to_join_course, before_action :user_course_identity, except: [:join_excellent_course, :index, :create, :new, :apply_to_join_course,
:search_course_list, :get_historical_course_students, :mine, :search_slim, :board_list] :search_course_list, :get_historical_course_students, :mine, :search_slim, :board_list]
before_action :teacher_allowed, only: [:update, :destroy, :settings, :search_teacher_candidate, before_action :teacher_allowed, only: [:update, :destroy, :settings, :search_teacher_candidate,
@ -114,7 +114,7 @@ class CoursesController < ApplicationController
#sql = "left join videos on videos.id=course_videos.video_id AND (videos.transcoded=1 OR videos.user_id = #{current_user.id})" #sql = "left join videos on videos.id=course_videos.video_id AND (videos.transcoded=1 OR videos.user_id = #{current_user.id})"
#@videos = paginate videos.joins(sql).includes(video: [user: :user_extension], user: :user_extension) #@videos = paginate videos.joins(sql).includes(video: [user: :user_extension], user: :user_extension)
videos = videos.includes(video: [user: :user_extension], user: :user_extension) videos = videos.includes(video: [user: :user_extension],user: :user_extension).select("course_videos.id, course_videos.title, course_videos.link, course_videos.user_id")
videos = videos.where(videos: {transcoded: true}) videos = videos.where(videos: {transcoded: true})
.or(videos.where(videos: {user_id: current_user.id})) .or(videos.where(videos: {user_id: current_user.id}))
.or(videos.where(course_videos: {is_link: true})) .or(videos.where(course_videos: {is_link: true}))
@ -1297,7 +1297,7 @@ class CoursesController < ApplicationController
def left_banner def left_banner
@user = current_user @user = current_user
@is_teacher = @user_course_identity < Course::ASSISTANT_PROFESSOR @is_teacher = @user_course_identity < Course::ASSISTANT_PROFESSOR
@course_modules = @course.course_modules.where(hidden: 0).includes(first_categories: :children) @course_modules = @course.course_modules.where.not(module_type: 'attendance').where(hidden: 0).includes(first_categories: :children)
@hidden_modules = @course.course_modules.where(hidden: 1) @hidden_modules = @course.course_modules.where(hidden: 1)
@second_category_type = ["shixun_homework", "graduation", "attachment", "board", "course_group", "video", "common_homework", "group_homework"] @second_category_type = ["shixun_homework", "graduation", "attachment", "board", "course_group", "video", "common_homework", "group_homework"]
end end
@ -1481,6 +1481,23 @@ class CoursesController < ApplicationController
end end
end end
def watch_video_histories
@videos = CourseVideo.find_by_sql("
SELECT course_videos.id, videos.user_id, videos.title, IFNULL(hisotries.time,0) AS time, IFNULL(hisotries.num,0) AS num
FROM course_videos
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
FROM watch_course_videos
JOIN course_videos ON course_videos.id = watch_course_videos.course_video_id
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
")
@count = @videos.count
@videos = paginate @videos
end
private private
# Use callbacks to share common setup or constraints between actions. # Use callbacks to share common setup or constraints between actions.

@ -367,9 +367,9 @@ class FilesController < ApplicationController
@category_name = category.try(:module_name) @category_name = category.try(:module_name)
else else
@category = CourseSecondCategory.find category_id @category = CourseSecondCategory.find category_id
@category_id = category.try(:id) @category_id = @category.try(:id)
@category_name = category.try(:name) @category_name = @category.try(:name)
@parent_category_id = category&.parent_id.to_i @parent_category_id = @category&.parent_id.to_i
end end
end end

@ -12,7 +12,14 @@ class MemosController < ApplicationController
def index def index
@user = current_user @user = current_user
@memos = Memo.all @memos = Memo.all
s_order = (params[:order] == "replies_count" ? "all_replies_count" : params[:order]) || "updated_at" # replies_count created_at updated_at
s_order =
case params[:order]
when 'replies_count' then 'all_replies_count'
when 'created_at' then 'created_at'
else
'updated_at'
end
# @tidding_count = unviewed_tiddings(current_user) if current_user.present? # @tidding_count = unviewed_tiddings(current_user) if current_user.present?
page = params[:page] || 1 page = params[:page] || 1
limit = params[:limit] || 15 limit = params[:limit] || 15

@ -70,7 +70,7 @@ class ShixunsController < ApplicationController
end end
## 排序参数 ## 排序参数
bsort = params[:sort] || 'desc' bsort = (params[:sort] == "desc" ? "desc" : "asc")
case params[:order_by] || 'new' case params[:order_by] || 'new'
when 'hot' when 'hot'
@shixuns = @shixuns.order("shixuns.public = 2 desc, shixuns.myshixuns_count #{bsort}") @shixuns = @shixuns.order("shixuns.public = 2 desc, shixuns.myshixuns_count #{bsort}")

@ -5,6 +5,6 @@ class WatchVideoHistoriesController < ApplicationController
watch_log = CreateWatchVideoService.new(current_user, request, params).call watch_log = CreateWatchVideoService.new(current_user, request, params).call
render_ok(log_id: watch_log&.id) render_ok(log_id: watch_log&.id)
rescue CreateWatchVideoService::Error => ex rescue CreateWatchVideoService::Error => ex
render_error(ex.message) render_ok(log_id: watch_log&.id)
end end
end end

@ -14,6 +14,9 @@ class Weapps::CourseMemberAttendancesController < ApplicationController
@members = @members.where(course_group_id: params[:group_ids]) @members = @members.where(course_group_id: params[:group_ids])
end end
@page = params[:page] || 1
@limit = params[:limit] || 5
if params[:attendance_status].present? if params[:attendance_status].present?
@members = @members.joins(:course_member_attendances).where(course_member_attendances: {course_attendance_id: attendance.id, attendance_status: params[:attendance_status]}) @members = @members.joins(:course_member_attendances).where(course_member_attendances: {course_attendance_id: attendance.id, attendance_status: params[:attendance_status]})
end end
@ -34,7 +37,7 @@ class Weapps::CourseMemberAttendancesController < ApplicationController
if params[:attendance_mode] == "QUICK" if params[:attendance_mode] == "QUICK"
attendance = CourseAttendance.find_by(id: params[:attendance_id]) attendance = CourseAttendance.find_by(id: params[:attendance_id])
else else
attendance = CourseAttendance.find_by(attendance_code: params[:code]) attendance = CourseAttendance.find_by(id: params[:attendance_id], attendance_code: params[:code])
end end
tip_exception("该签到不存在") if attendance.blank? || attendance.course.blank? tip_exception("该签到不存在") if attendance.blank? || attendance.course.blank?

@ -82,7 +82,7 @@ module CoursesHelper
when "video" when "video"
"/classrooms/#{course.id}/course_videos" "/classrooms/#{course.id}/course_videos"
when "attendance" when "attendance"
"/classrooms/#{course.id}/signin" "/classrooms/#{course.id}/attendances"
end end
end end

@ -8,7 +8,7 @@ class Weapps::SubjectQuery < ApplicationQuery
end end
def call def call
subjects = @current_laboratory.subjects.unhidden.publiced subjects = @current_laboratory.subjects.unhidden.publiced.show_moblied
# 课程体系的过滤 # 课程体系的过滤
if params[:sub_discipline_id].present? if params[:sub_discipline_id].present?
@ -21,7 +21,7 @@ class Weapps::SubjectQuery < ApplicationQuery
# 搜索 # 搜索
if params[:keyword].present? if params[:keyword].present?
subjects = subjects.where("subjects.name like '%#{params[:keyword]}%'") subjects = subjects.where("subjects.name like :keyword", keyword: "%#{params[:keyword]}%")
end end
subjects = subjects.left_joins(:shixuns, :repertoire).select('subjects.id, subjects.name, subjects.excellent, subjects.stages_count, subjects.status, subjects.homepage_show, subjects = subjects.left_joins(:shixuns, :repertoire).select('subjects.id, subjects.name, subjects.excellent, subjects.stages_count, subjects.status, subjects.homepage_show,
@ -33,10 +33,10 @@ class Weapps::SubjectQuery < ApplicationQuery
private private
def order_type def order_type
params[:order] || "updated_at" params[:order] == "updated_at" ? "updated_at" : "myshixuns_count"
end end
def sort_type def sort_type
params[:sort] || "desc" params[:sort] == "desc" ? "desc" : "asc"
end end
end end

@ -10,29 +10,36 @@ class CreateWatchVideoService < ApplicationService
def call def call
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
current_time = Time.now current_time = Time.now
params[:watch_duration] = params[:watch_duration].to_f.round(2)
params[:total_duration] = params[:total_duration].to_f.round(2)
params[:duration] = params[:duration].to_f.round(2)
if params[:log_id].present? if params[:log_id].present?
if params[:total_duration].to_f < params[:watch_duration].to_f || params[:watch_duration].to_f < 0 watch_video_history = user.watch_video_histories.find(params[:log_id])
raise Error, '观看时长错误' if params[:total_duration] < params[:watch_duration]
return watch_video_history
end end
# 更新观看时长 # 更新观看时长
watch_video_history = user.watch_video_histories.find(params[:log_id]) if watch_video_history.present? && !watch_video_history.is_finished && watch_video_history.watch_duration <= params[:watch_duration] && watch_video_history.total_duration <= params[:total_duration]
if watch_video_history.present? && watch_video_history.watch_duration <= params[:watch_duration].to_f && params[:total_duration].to_f > watch_video_history.total_duration
# 如果观看总时长没变,说明视频没有播放,无需再去记录 # 如果观看总时长没变,说明视频没有播放,无需再去记录
watch_video_history.end_at = current_time watch_video_history.end_at = current_time
watch_video_history.total_duration = params[:total_duration] watch_video_history.total_duration = params[:total_duration]
watch_video_history.watch_duration = params[:watch_duration].to_f > watch_video_history.duration ? watch_video_history.duration : params[:watch_duration] watch_video_history.watch_duration = params[:watch_duration] > watch_video_history.duration ? watch_video_history.duration : params[:watch_duration]
watch_video_history.is_finished = (watch_video_history.duration <= params[:watch_duration].to_f) watch_video_history.is_finished = params[:ed].present?
watch_video_history.save! watch_video_history.save!
watch_course_video = watch_video_history.watch_course_video watch_course_video = watch_video_history.watch_course_video
if watch_course_video.present? && !watch_course_video.is_finished && watch_course_video.watch_duration < params[:watch_duration].to_f if watch_course_video.present?
watch_course_video.total_duration = watch_course_video.watch_video_histories.sum(:total_duration)
watch_course_video.end_at = current_time
if !watch_course_video.is_finished && watch_course_video.watch_duration < params[:watch_duration]
# 更新课程视频的时长及是否看完状态 # 更新课程视频的时长及是否看完状态
watch_course_video.watch_duration = params[:watch_duration] watch_course_video.watch_duration = params[:watch_duration]
watch_course_video.is_finished = (watch_course_video.duration <= params[:watch_duration].to_f) if params[:ed].present?
watch_course_video.end_at = current_time watch_course_video.is_finished = watch_course_video.total_duration >= watch_course_video.duration
end
end
watch_course_video.save! watch_course_video.save!
end end
end end
@ -46,10 +53,9 @@ class CreateWatchVideoService < ApplicationService
d.duration = params[:duration] d.duration = params[:duration]
end end
watch_course_video.save! unless watch_course_video.persisted?
watch_video_history = build_video_log(current_time, course_video.video_id, watch_course_video.id) watch_video_history = build_video_log(current_time, course_video.video_id, watch_course_video.id)
watch_video_history.save! watch_video_history.save!
watch_course_video.save! unless watch_course_video.persisted?
else else
# 非课堂视频 # 非课堂视频
video = Video.find(params[:video_id]) video = Video.find(params[:video_id])

@ -1,5 +1,5 @@
json.attendances @attendances do |attendance| json.attendances @attendances do |attendance|
json.(attendance, :id, :name, :normal_count, :all_count, :mode) json.(attendance, :id, :name, :normal_count, :all_count, :mode, :attendance_code)
json.author do json.author do
user = attendance.user user = attendance.user
json.user_name user.real_name json.user_name user.real_name

@ -10,6 +10,8 @@ json.videos @videos do |video|
json.user_login user&.login json.user_login user&.login
else else
json.partial! 'users/videos/video', locals: { video: video.video } json.partial! 'users/videos/video', locals: { video: video.video }
json.total_time video.watch_course_videos.sum(:total_duration).round(0)
json.people_num video.watch_course_videos.count(:user_id)
end end
end end

@ -0,0 +1,10 @@
json.videos do
json.array! @videos do |v|
json.id v.id
json.title v.title
json.user_name v.user&.real_name
json.people_num v.num
json.total_time v.time
end
end
json.count @count

@ -4,8 +4,9 @@
# json.student_id member.user&.student_id # json.student_id member.user&.student_id
# end # end
json.member_attendances @members.each do |member| json.member_attendances @members.each_with_index.to_a do |member, index|
json.(member, :user_id) json.(member, :user_id)
json.index (@page.to_i - 1) * @limit.to_i + index + 1
json.user_name member.user&.real_name json.user_name member.user&.real_name
json.student_id member.user&.student_id json.student_id member.user&.student_id
json.attendance_status @member_attendances.select{|attendance| attendance.course_member_id == member.id}.first&.attendance_status || "ABSENCE" json.attendance_status @member_attendances.select{|attendance| attendance.course_member_id == member.id}.first&.attendance_status || "ABSENCE"

@ -531,6 +531,7 @@ Rails.application.routes.draw do
post :inform_up post :inform_up
post :inform_down post :inform_down
get :calculate_all_shixun_scores get :calculate_all_shixun_scores
get :watch_video_histories
end end
collection do collection do

@ -0,0 +1,8 @@
class AddTotalDurationToWatchCourseDuration < ActiveRecord::Migration[5.2]
def change
add_column :watch_course_videos, :total_duration, :float, default: 0
WatchVideoHistory.where("created_at < '2020-03-14 00:00:00'").each do |d|
d.watch_course_video.increment!(:total_duration, d.total_duration) if d.watch_course_video.present?
end
end
end

@ -13577,6 +13577,21 @@
"resolved": "http://registry.npm.taobao.org/q/download/q-1.5.1.tgz", "resolved": "http://registry.npm.taobao.org/q/download/q-1.5.1.tgz",
"integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=" "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc="
}, },
"qr.js": {
"version": "0.0.0",
"resolved": "https://registry.npm.taobao.org/qr.js/download/qr.js-0.0.0.tgz",
"integrity": "sha1-ys6GOG9ZoNuAUPqQ2baw6IoeNk8="
},
"qrcode.react": {
"version": "1.0.0",
"resolved": "https://registry.npm.taobao.org/qrcode.react/download/qrcode.react-1.0.0.tgz",
"integrity": "sha1-foiJ2zt2nlVejrRj1MbeIhw21d4=",
"requires": {
"loose-envify": "^1.4.0",
"prop-types": "^15.6.0",
"qr.js": "0.0.0"
}
},
"qs": { "qs": {
"version": "6.7.0", "version": "6.7.0",
"resolved": "http://registry.npm.taobao.org/qs/download/qs-6.7.0.tgz", "resolved": "http://registry.npm.taobao.org/qs/download/qs-6.7.0.tgz",

@ -38,6 +38,36 @@ export function getNextHalfHourOfMoment(moment) {
return moment return moment
} }
 export function formatSeconds(value) {
        var theTime = parseInt(value);// 秒
        var middle= 0;// 分
        var hour= 0;// 小时
    
        if(theTime > 60) {
            middle= parseInt(theTime/60);
            theTime = parseInt(theTime%60);
            if(middle> 60) {
                hour= parseInt(middle/60);
                middle= parseInt(middle%60);
            }
        }
        var result = ""+parseInt(theTime)+"秒";
        if(middle > 0) {
if(hour>0){
result = ""+parseInt(middle)+"分";
}else{
result = ""+parseInt(middle)+"分"+result;
}
            
        }
        if(hour> 0) {
            result = ""+parseInt(hour)+"小时"+result;
        }
        return result;
    }
export function formatDuring(mss){ export function formatDuring(mss){
var days = parseInt(mss / (1000 * 60 * 60 * 24)); var days = parseInt(mss / (1000 * 60 * 60 * 24));
var hours = parseInt((mss % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); var hours = parseInt((mss % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));

@ -20,7 +20,7 @@ export { bytesToSize as bytesToSize } from './UnitUtil';
export { markdownToHTML, uploadNameSizeSeperator, appendFileSizeToUploadFile, appendFileSizeToUploadFileAll, isImageExtension, export { markdownToHTML, uploadNameSizeSeperator, appendFileSizeToUploadFile, appendFileSizeToUploadFileAll, isImageExtension,
downloadFile, sortDirections } from './TextUtil' downloadFile, sortDirections } from './TextUtil'
export { handleDateString, getNextHalfHourOfMoment,formatDuring } from './DateUtil' export { handleDateString, getNextHalfHourOfMoment,formatDuring,formatSeconds} from './DateUtil'
export { configShareForIndex, configShareForPaths, configShareForShixuns, configShareForCourses, configShareForCustom } from './util/ShareUtil' export { configShareForIndex, configShareForPaths, configShareForShixuns, configShareForCourses, configShareForCustom } from './util/ShareUtil'

@ -240,8 +240,12 @@ class Video extends Component {
{ {
videos && videos.length > 0 ? videos && videos.length > 0 ?
<React.Fragment> <React.Fragment>
<div style={{display:'flex'}}>
<p className="font-grey-9 mt20 mb20 pl5"> <span className="color-orange">{videoData && videoData.count}</span> </p> <p className="font-grey-9 mt20 mb20 pl5"> <span className="color-orange">{videoData && videoData.count}</span> </p>
<p className="mt20 mb20 pl5" style={{marginLeft:'auto',color:'#C0C4CC'}}>播放数据从2020-03-13 24:00开始统计</p>
</div>
<div className="videoContent"> <div className="videoContent">
{ {
videos.map((item, key) => { videos.map((item, key) => {

@ -43,7 +43,7 @@ export default ({ src, videoId, logWatchHistory, courseId = null }) => {
let isSeeking = false let isSeeking = false
let pos = []// let pos = []//
const log = useCallback((callback) => { const log = useCallback((callback, isEnd = false) => {
let params = {} let params = {}
if (logId) { if (logId) {
params['log_id'] = logId params['log_id'] = logId
@ -59,6 +59,9 @@ export default ({ src, videoId, logWatchHistory, courseId = null }) => {
params['duration'] = totalDuration params['duration'] = totalDuration
params['device'] = device params['device'] = device
} }
if (isEnd) {
params['ed'] = "1"
}
async function getLogId() { async function getLogId() {
isLoging = true isLoging = true
let id = await logWatchHistory(params) let id = await logWatchHistory(params)
@ -108,18 +111,15 @@ export default ({ src, videoId, logWatchHistory, courseId = null }) => {
log() log()
} }
} }
//
async function onEnded() { async function onEnded() {
log(() => { log(() => {
logId = null logId = null
logCount = 1
lastUpdatedTime = 0 lastUpdatedTime = 0
sumTimePlayed = 0
initLog = false initLog = false
isLoging = false isLoging = false
isSeeking = false isSeeking = false
pos = [] }, true)
})
} }
function onTimeupdate() { function onTimeupdate() {
@ -137,6 +137,8 @@ export default ({ src, videoId, logWatchHistory, courseId = null }) => {
log() log()
} }
} }
}else {
lastUpdatedTime = newTime
} }
} }

@ -23,9 +23,7 @@ class Signinstatistics extends Component {
} }
} }
getdata=(group_id)=>{ getdata=(group_id)=>{
this.setState({
spal:true
})
const coursesId=this.props.match.params.coursesId; const coursesId=this.props.match.params.coursesId;
let url=`/weapps/courses/${coursesId}/attendances.json` let url=`/weapps/courses/${coursesId}/attendances.json`
axios.get(url,{params:{ axios.get(url,{params:{
@ -77,6 +75,9 @@ class Signinstatistics extends Component {
} }
componentDidMount() { componentDidMount() {
this.setState({
spal:true
})
const coursesId=this.props.match.params.coursesId; const coursesId=this.props.match.params.coursesId;
let newurl=`/courses/${coursesId}/all_course_groups.json`; let newurl=`/courses/${coursesId}/all_course_groups.json`;
axios.get(newurl).then((response) => { axios.get(newurl).then((response) => {
@ -125,16 +126,16 @@ class Signinstatistics extends Component {
{ {
` `
.lishiqiandao{ .lishiqiandao{
background-image: url(${getImageUrl(`/images/qiandao/lishi.png`)}); background-image: url(${getImageUrl(`images/qiandao/lishi.png`)});
} }
.daokeqiandao{ .daokeqiandao{
background-image: url(${getImageUrl(`/images/qiandao/daoke.png`)}); background-image: url(${getImageUrl(`images/qiandao/daoke.png`)});
} }
.kuangkeqiandao{ .kuangkeqiandao{
background-image: url(${getImageUrl(`/images/qiandao/kuangke.png`)}); background-image: url(${getImageUrl(`images/qiandao/kuangke.png`)});
} }
.qingjiaqiandao{ .qingjiaqiandao{
background-image: url(${getImageUrl(`/images/qiandao/qingjia.png`)}); background-image: url(${getImageUrl(`images/qiandao/qingjia.png`)});
} }
` `
} }

@ -36,7 +36,7 @@ class Teacherentry extends Component {
<React.Fragment> <React.Fragment>
<div className={index===0?"ws100s edu-back-white ": "ws100s edu-back-white mt20"}> <div className={index===0?"ws100s edu-back-white ": "ws100s edu-back-white mt20"}>
<div className="ws100s teacherentrydiv "> <div className="ws100s teacherentrydiv ">
<p className="ws100s teachedivp ymaxnamewidthdivp xiaoshou" onClick={()=>this.props.qiandaoxiangq(true,item.id)}> <p className={isAdmin?"ws100s teachedivp ymaxnamewidthdivp xiaoshou":"ws100s teachedivp ymaxnamewidthdivp"} onClick={isAdmin?()=>this.props.qiandaoxiangq(true,item.id):""}>
{ {
item.name item.name
} }

@ -162,3 +162,27 @@
.textcenter{ .textcenter{
text-align: center !important; 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;
}

@ -21,14 +21,14 @@ class Signedinlist extends Component {
attendance_status:undefined, attendance_status:undefined,
state:[ state:[
{id:undefined,name:"全部状态"}, {id:undefined,name:"全部状态"},
{id:"NORMAL",name:"正常出勤"}, {id:"NORMAL",name:"正常签到"},
{id:"LEAVE",name:"请假"}, {id:"LEAVE",name:"请 假"},
{id:"ABSENCE",name:"旷课"}, {id:"ABSENCE",name:"旷 课"},
], ],
newstate:[ newstate:[
{id:"NORMAL",name:"正常出勤"}, {id:"NORMAL",name:"正常签到"},
{id:"LEAVE",name:"请假"}, {id:"LEAVE",name:"请 假"},
{id:"ABSENCE",name:"旷课"}, {id:"ABSENCE",name:"旷 课"},
], ],
course_members_count:'--', course_members_count:'--',
attendance_count:'--', attendance_count:'--',
@ -36,31 +36,36 @@ class Signedinlist extends Component {
} }
componentDidMount() { componentDidMount() {
this.getdatas(this.props&&this.props.switattendance_id,1,[],undefined)
// this.getpath()
}
componentDidUpdate(prevProps, prevState) {
if(prevProps.headdata!=this.props.headdata){
let {attendanceslist}=this.state; let {attendanceslist}=this.state;
if(this.props.headdata){ if(this.props.headdata){
let listattendanceslist=attendanceslist; let listattendanceslist=attendanceslist;
if(headdata.course_groups){ if(this.props.headdata.course_groups){
if(headdata.course_groups.length>0){ if(this.props.headdata.course_groups.length>0){
headdata.course_groups.map((item,key)=>{ this.props.headdata.course_groups.map((item,key)=>{
listattendanceslist.push(item) listattendanceslist.push(item)
}) })
} }
} }
this.setState({ this.setState({
listattendanceslist:listattendanceslist, listattendanceslist:listattendanceslist,
data:response.data, data:this.props.headdata,
course_members_count:headdata.all_count, course_members_count:this.props.headdata.normal_count,
attendance_count:headdata.normal_count attendance_count:this.props.headdata.all_count
}) })
} }
this.getdatas(this.props&&this.props.switattendance_id,1,[],undefined)
// this.getpath()
} }
}
getdatas=(id,page,group_ids,attendance_status)=>{ getdatas=(id,page,group_ids,attendance_status)=>{
this.setState({ this.setState({
loading:true, loading:true,
@ -101,24 +106,25 @@ class Signedinlist extends Component {
neval=[] neval=[]
this.setState({ this.setState({
group_ids: [], group_ids: [],
page:1
}) })
}else{ }else{
neval=[value] neval=[value]
this.setState({ this.setState({
group_ids: [value], group_ids: [value],
page:1
}) })
} }
let {page,attendance_status}=this.state; let {page,attendance_status}=this.state;
this.getdatas(this.props&&this.props.switattendance_id,page,neval,attendance_status) this.getdatas(this.props&&this.props.switattendance_id,1,neval,attendance_status)
if(this.props.defaultActiveKey==="1"){ if(this.props.defaultActiveKey==="1"){
this.getpath(value) this.getpath(value)
} }
} }
getpath=(id)=>{ getpath=(id)=>{
let {attendanceslist}=this.state; let listattendanceslist=[]
let listattendanceslist=attendanceslist
let url=`/weapps/attendances/${this.props&&this.props.switattendance_id}.json`; let url=`/weapps/attendances/${this.props&&this.props.switattendance_id}.json`;
axios.get(url).then((response) => { axios.get(url).then((response) => {
if(response.data){ if(response.data){
@ -140,12 +146,12 @@ class Signedinlist extends Component {
}) })
}else{ }else{
this.setState({ this.setState({
course_members_count:response.data.all_count, course_members_count:response.data.normal_count,
attendance_count: response.data.normal_count attendance_count: response.data.all_count
}) })
} }
this.setState({ this.setState({
listattendanceslist:attendanceslist, listattendanceslist:listattendanceslist,
data:response.data data:response.data
}) })
@ -160,16 +166,18 @@ class Signedinlist extends Component {
neval=undefined neval=undefined
this.setState({ this.setState({
attendance_status:undefined, attendance_status:undefined,
page:1
}) })
}else{ }else{
neval=value neval=value
this.setState({ this.setState({
attendance_status: value, attendance_status: value,
page:1
}) })
} }
let {page,group_ids}=this.state; let {page,group_ids}=this.state;
this.getdatas(this.props&&this.props.switattendance_id,page,group_ids,neval) this.getdatas(this.props&&this.props.switattendance_id,1,group_ids,neval)
} }
paginationonChange = (pageNumber) => { paginationonChange = (pageNumber) => {
this.setState({ this.setState({
@ -181,6 +189,17 @@ class Signedinlist extends Component {
} }
handleChange=(attendance_status,value)=>{ 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`; let url=`/weapps/course_member_attendances/update_status.json`;
axios.post(url, { axios.post(url, {
@ -192,7 +211,9 @@ class Signedinlist extends Component {
.then((response) => { .then((response) => {
if (response.data.status == 0) { if (response.data.status == 0) {
this.props.showNotification(`修改状态成功`); this.props.showNotification(`修改状态成功`);
this.setState({
member_attendances:newmember_attendances
})
} }
}) })
.catch(function (error) { .catch(function (error) {
@ -203,38 +224,54 @@ class Signedinlist extends Component {
} }
render() { render() {
let {attendanceslist,state,data,member_attendances,newstate}=this.state; let {attendanceslist,state,data,member_attendances,newstate,attendance_status}=this.state;
const columns = [ const columns = [
{ {
title: '序号', title: '序号',
dataIndex: 'index', dataIndex: 'index',
key: 'index', key: 'index',
width:300,
className: "textcenter", className: "textcenter",
}, },
{ {
title: '姓名', title: '姓名',
dataIndex: 'user_name', dataIndex: 'user_name',
key: 'user_name', key: 'user_name',
width:300,
className: "textcenter", className: "textcenter",
render: (text, record) => (
<span>{record.user_name===null?"--":record.user_name}</span>
)
}, },
{ {
title: '学号', title: '学号',
dataIndex: 'student_id', dataIndex: 'student_id',
key: 'student_id', key: 'student_id',
width:300,
className: "textcenter", className: "textcenter",
render: (text, record) => (
<span>{record.student_id===null?"--":record.student_id}</span>
)
}, },
{ {
title: '状态', title: '状态',
key: 'attendance_status', key: 'attendance_status',
width:300,
dataIndex: 'attendance_status', dataIndex: 'attendance_status',
className: "textcenter",
render: (text, record) => ( render: (text, record) => (
<span> <span>
<Select key={record.index} defaultValue={record.attendance_status} className={"Signedinlistbox"} style={{ width: 167 }} onChange={(e)=>this.handleChange(e,record.user_id)}> <Select key={record.index} defaultValue={record.attendance_status}
// className={"Signedinlistbox"}
className={record.attendance_status==="NORMAL"?"color26C7C9 Signedinlistbox sginboxcolor26C7C9":record.attendance_status==="LEAVE"?"colorEAAE4E Signedinlistbox sginboxcolorEAAE4E":record.attendance_status==="ABSENCE"?"colorFF835C Signedinlistbox sginboxcolorFF835C":"Signedinlistbox"}
style={{ width: 167 }} onChange={(e)=>this.handleChange(e,record.user_id)}>
{ {
newstate&&newstate.map((item,key)=>{ newstate&&newstate.map((item,key)=>{
return( return(
<Option value={item.id} key={key}>{item.name}</Option> <Option value={item.id} key={key}
className={item.name==="正常签到"?"color26C7C9 sginbox":item.name==="请 假"?"colorEAAE4E sginbox":item.name==="旷 课"?"colorFF835C sginbox":""}>{item.name}</Option>
) )
}) })
} }
@ -265,11 +302,18 @@ class Signedinlist extends Component {
<Col className="gutter-row ml20" span={6}> <Col className="gutter-row ml20" span={6}>
<Select defaultValue="全部状态" className={"Signedinlistbox"} style={{ width: 167 }} onChange={this.handleChangestate}> <Select defaultValue="全部状态"
className={"Signedinlistbox"}
//className={attendance_status&&attendance_status==="NORMAL"?"color26C7C9 Signedinlistbox sginboxcolor26C7C9":attendance_status&&attendance_status==="LEAVE"?"colorEAAE4E Signedinlistbox sginboxcolorEAAE4E":attendance_status&&attendance_status==="ABSENCE"?"colorFF835C Signedinlistbox sginboxcolorFF835C":"Signedinlistbox"}
style={{ width: 167 }} onChange={this.handleChangestate}>
{ {
state&&state.map((item,key)=>{ state&&state.map((item,key)=>{
return( return(
<Option value={item.id} key={key}>{item.name}</Option> <Option value={item.id} key={key}
//className={item.name==="正常签到"?"color26C7C9":item.name==="请假"?"colorEAAE4E":item.name==="旷课"?"colorFF835C":""}
>
{item.name}
</Option>
) )
}) })
} }

@ -25,8 +25,6 @@ class Signindetails extends Component{
//.log(response); //.log(response);
if(response){ if(response){
if(response.data){ if(response.data){
console.log("头部数据")
console.log(response.data)
this.setState({ this.setState({
headdata:response.data headdata:response.data
}) })
@ -37,12 +35,6 @@ class Signindetails extends Component{
} }
componentDidUpdate = (prevProps) => {
console.log("componentDidUpdate");
}
render(){ render(){
let {headdata}= this.state; let {headdata}= this.state;

@ -30,7 +30,7 @@ class ShixunPathSearch extends Component {
//适配器 //适配器
onChangeLabel(value) { onChangeLabel(value) {
let rs = value === 'new' ? 'updated_at' : 'myshixuns_scount' let rs = value === 'new' ? 'updated_at' : 'myshixuns_count'
let { discipline_id, sub_discipline_id } = this.state; let { discipline_id, sub_discipline_id } = this.state;
this.setState({ this.setState({
order: rs, order: rs,

@ -70,6 +70,7 @@
} }
.videoItem .time { .videoItem .time {
height: 15px;
color: #C0C4CC; color: #C0C4CC;
} }
.videoItem .square-main .buttonRow .dianjilianicon{ .videoItem .square-main .buttonRow .dianjilianicon{

@ -1,6 +1,6 @@
import React, { useState, useEffect, useContext, memo } from 'react'; import React, { useState, useEffect, useContext, memo } from 'react';
import { Progress, Input, Tooltip , Spin } from 'antd' 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 axios from 'axios'
import moment from 'moment' import moment from 'moment'
import playIcon from './images/play.png' import playIcon from './images/play.png'
@ -21,7 +21,7 @@ const clipboardMap = {}
function VideoInReviewItem (props) { function VideoInReviewItem (props) {
const theme = useContext(ThemeContext); const theme = useContext(ThemeContext);
const { history, file_url , play_url , cover_url , transcoded , title, created_at, published_at, isReview, id 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(()=> { useEffect(()=> {
if (!isReview) { if (!isReview) {
_clipboard = new ClipboardJS(`.copybtn_item_${id}`); _clipboard = new ClipboardJS(`.copybtn_item_${id}`);
@ -37,6 +37,9 @@ function VideoInReviewItem (props) {
} }
} }
}, []) }, [])
const username = props.match.params.username const username = props.match.params.username
function toList() { function toList() {
history.push(`/users/${username}/videos`) history.push(`/users/${username}/videos`)
@ -60,7 +63,7 @@ function VideoInReviewItem (props) {
{!isReview && !link && transcoded && {!isReview && !link && transcoded &&
<div className="playWrap" onClick={() => onMaskClick(props)}> <div className="playWrap" onClick={() => onMaskClick(props)}>
<img className="play mp23" src={playIcon}></img> <img className="play mp23" src={playIcon}></img>
{play_duration===0?"":<div className={"play_duration"}>累计学习时长{play_duration} h</div>} {/* {play_duration===0?"":<div className={"play_duration"}>累计学习时长:{play_duration} h</div>} */}
</div> </div>
} }
</Spin> </Spin>
@ -69,16 +72,22 @@ function VideoInReviewItem (props) {
title={title && title.length > 20 ? title : ''} title={title && title.length > 20 ? title : ''}
>{title}</div> >{title}</div>
<div className="df buttonRow mb10"> <div className="df buttonRow mb10">
{/* <div className={"play_duration"}>累计学习时长:{play_duration} h</div> */}
<span className="time">{moment(published_at || created_at).format('YYYY-MM-DD HH:mm:ss')}</span> {/* <span className="time">{moment(published_at || created_at).format('YYYY-MM-DD HH:mm:ss')}{people_num}</span> */}
{link ?<span className="time"> </span>:<span className="time">{
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' */}
</span>}
</div> </div>
<div className="df buttonRow"> <div className="df buttonRow">
{/* 2019-09-01 10:00:22 */} {/* 2019-09-01 10:00:22 */}
<span className={"dianjilianicon"}> <span className={"dianjilianicon"}>
{!vv || (vv && vv)===0 ? "" : <Tooltip title="播放次数" placement="bottom"> {!people_num || (people_num && people_num)===0 ? "" : <Tooltip title="观看人数" placement="bottom">
<i className={`icon-dianjiliang iconfont dianjilianicon`}></i> <i className={`icon-dianjiliang iconfont dianjilianicon font-12`}> {!people_num || (people_num && people_num)===0?"":people_num}</i>
</Tooltip> } {!vv || (vv && vv)===0?"":vv} </Tooltip> }
</span> </span>
<div> <div>
{ {
isReview !== true && moveVideo && isReview !== true && moveVideo &&

Loading…
Cancel
Save