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

courseware
杨树林 5 years ago
commit 3c6d8d1e6c

@ -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_course_videos.course_video_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.id, watch_course_videos.user_id, watch_course_videos.start_at, watch_course_videos.end_at, watch_course_videos.is_finished, watch_course_videos.total_duration")
if params[:order].present?
key = params[:order].split("-")

@ -105,7 +105,8 @@ class CoursesController < ApplicationController
def course_videos
course_videos = @course.course_videos
course_videos = course_videos.joins("
JOIN videos ON course_videos.video_id = videos.id
LEFT JOIN videos ON course_videos.video_id = videos.id AND
((videos.transcoded = TRUE OR videos.user_id = #{current_user.id}) OR course_videos.is_link = TRUE)
LEFT JOIN (
SELECT watch_course_videos.course_video_id,
SUM(watch_course_videos.total_duration) AS total_duration,
@ -116,7 +117,7 @@ class CoursesController < ApplicationController
WHERE course_videos.course_id = #{@course.id}
GROUP BY watch_course_videos.course_video_id
) AS watch_courses ON watch_courses.course_video_id = course_videos.id
").where("((videos.transcoded = TRUE OR videos.user_id = #{current_user.id}) OR course_videos.is_link = TRUE)")
")
@video_module = @course.course_modules.find_by(module_type: "video")
@ -132,7 +133,7 @@ class CoursesController < ApplicationController
@count = course_videos.count("course_videos.id")
logger.info("#######count:#{@count}")
course_videos = course_videos.select("IFNULL(watch_courses.total_duration, 0) AS total_duration, IFNULL(watch_courses.count,0) AS count, course_videos.video_id, course_videos.title, course_videos.is_link, course_videos.user_id")
course_videos = course_videos.select("course_videos.id, IFNULL(watch_courses.total_duration, 0) AS total_duration, IFNULL(watch_courses.count,0) AS count, course_videos.video_id, course_videos.title, course_videos.link, course_videos.is_link, course_videos.user_id")
@videos = paginate course_videos
end
@ -1520,7 +1521,7 @@ class CoursesController < ApplicationController
end
end
@videos = @videos.select("course_videos.id, videos.user_id, videos.title, IFNULL(hisotries.time,0) AS total_time, IFNULL(hisotries.num,0) AS people_num")
@videos = @videos.select("course_videos.id, videos.user_id, videos.title AS video_title, IFNULL(hisotries.time,0) AS total_time, IFNULL(hisotries.num,0) AS people_num")
@videos = paginate @videos
end
@ -1533,14 +1534,14 @@ 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_video_histories.watch_course_video_id) AS num
SELECT watch_course_videos.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")
GROUP BY watch_course_videos.id
) AS hisotries ON hisotries.id = watch_course_videos.id ").select("course_videos.id")
@count = @videos.count
@ -1553,7 +1554,7 @@ class CoursesController < ApplicationController
end
end
@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 = @videos.select("course_videos.id, watch_course_videos.id AS watch_course_video_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

@ -115,7 +115,7 @@ class Attachment < ApplicationRecord
def become_history
history = self.attachment_histories.first
new_attachment_history = AttachmentHistory.new(self.attributes.except("id", "resource_bank_id", "unified_setting", "course_second_category_id", "delay_publish").merge(
new_attachment_history = AttachmentHistory.new(self.attributes.except("id", "resource_bank_id", "unified_setting", "course_second_category_id", "delay_publish", "link").merge(
attachment_id: self.id,
version: history.nil? ? 1 : history.version + 1,
))
@ -123,7 +123,7 @@ class Attachment < ApplicationRecord
end
def copy_attributes_from_new_attachment(new_attachment)
self.attributes = new_attachment.attributes.dup.except("id","container_id","container_type","is_public","downloads", "quotes",'is_publish','publish_time', "delay_publish")
self.attributes = new_attachment.attributes.dup.except("id","container_id","container_type","is_public","downloads", "quotes",'is_publish','publish_time', "delay_publish", "link")
end
def set_public(is_public)

@ -161,7 +161,7 @@ class Course < ApplicationRecord
end
def videos_count
course_videos.where(video_id: videos.where("transcoded = 1 or videos.user_id = #{User.current.id}").pluck(:id))
course_videos.where(video_id: videos.where("transcoded = 1"))
.or(course_videos.where(course_videos: {is_link: true})).size
end

@ -1,5 +1,6 @@
json.data do
json.array! @watch_course_videos do |d|
json.id d.id
json.user_name d.user&.real_name
json.is_finished d.is_finished ? true : false
json.total_duration d.total_duration.round(0)

@ -9,6 +9,7 @@ json.videos @videos do |video|
json.user_img url_to_avatar(user)
json.user_login user&.login
else
json.course_video_id video.id
json.partial! 'users/videos/video', locals: { video: video.video }
json.total_time video['total_duration'].round(0)
json.people_num video['count']

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

@ -1,7 +1,7 @@
json.videos do
json.array! @videos do |v|
json.id v.id
json.title v.title
json.title v['video_title']
json.user_name v.user&.real_name
json.people_num v['people_num']
json.total_time v['total_time'].round(0)

@ -255,11 +255,13 @@ class Video extends Component {
<div className="videoContent">
{
videos.map((item, key) => {
console.log(course_identity > 2 && item.user_id === user_id)
//console.log(course_identity > 2 && item.user_id === user_id)
return (
<VideoInReviewItem
Setmyktid={(id,title)=>this.props.Setmyktid(id,title)}
mykt={this.props.mykt}
{...this.props}
{...this.state}
{...item}
key={item.id}
onEditVideo={this.onEditVideo}
@ -268,6 +270,8 @@ class Video extends Component {
operation={operation || item.user_id === user_id}
deleteVideo={(admin || item.user_id === user_id) ? this.deleteVideo : undefined}
moveVideo={videoData && videoData.has_category && flagMove ? () => this.moveVideo(item.id, (course_identity > 2 && item.user_id !== user_id)) : undefined}
newtitle={item.title}
newcourse_video_id={item.course_video_id}
>
</VideoInReviewItem>
)
@ -294,4 +298,4 @@ class Video extends Component {
)
}
}
export default Video;
export default Video;

@ -41,6 +41,8 @@ class VideoIndex extends Component {
liveVisible: false,
statistics: false,
myktid:null,
mytitle:''
}
}
@ -55,7 +57,24 @@ class VideoIndex extends Component {
this.getLiveList(page);
}
}
Setmyktid=(id,title)=>{
const isAdmin = this.props&& this.props.isAdmin();
if(isAdmin===true){
this.setState({
myktid:id,
statistics:true,
mytitle:title,
})
}else{
this.setState({
statistics:true,
myktid:null,
mytitle:"",
})
}
}
componentDidMount = () => {
const {search} = this.props.location;
const {page} = this.state;
@ -79,6 +98,8 @@ class VideoIndex extends Component {
if(this.props.homedirectory ===true){
this.setState({
statistics:false,
myktid:null,
mytitle:"",
})
}
}
@ -255,12 +276,23 @@ class VideoIndex extends Component {
this.setState({
statistics: bool,
myktid:null,
mytitle:"",
})
}
mystatisticsys = (bool,n) => {
this.setState({
statistics: bool,
myktid:null,
mytitle:"",
})
}
render() {
const {videos, upload, videoData, type, liveData, lives, page, liveVisible, isSpining, liveId, otherLinkVisible, statistics} = this.state;
const {videos, upload, videoData, type, liveData, lives, page, liveVisible, isSpining, liveId, otherLinkVisible, statistics,myktid,mytitle} = this.state;
const {coursesId, videoId} = this.props.match.params;
let {course_identity} = this.props && this.props.coursedata;
let is_teacher = this.props && this.props.user && this.props.user.is_teacher;
@ -377,7 +409,14 @@ class VideoIndex extends Component {
</div>
</div>
:
<Videostatistics {...this.props} {...this.state} statisticsy={(b) => this.statisticsy(b)}></Videostatistics>
(
myktid===null||myktid===undefined?
<Videostatistics {...this.props} {...this.state} statisticsy={(b) => this.statisticsy(b)}></Videostatistics>
:
<Videostatisticscomtwo {...this.state} {...this.props} tisid={myktid} mytitle={mytitle} tisticsbools={(b,id)=>this.mystatisticsys(b,id)}></Videostatisticscomtwo>
)
}
@ -387,6 +426,8 @@ class VideoIndex extends Component {
{
type === "video" ?
<Videos
mykt={"mykt"}
Setmyktid={(id,title)=>this.Setmyktid(id,title)}
upload={upload}
videos={videos}
page={page}

@ -472,7 +472,14 @@
white-space:nowrap;
cursor: default;
}
.maxnamewidth90s{
width: 90px;
max-width: 90px;
overflow:hidden;
text-overflow:ellipsis;
white-space:nowrap;
cursor: default;
}
.font-14{
font-size: 14px !important;
}

@ -33,6 +33,20 @@ class Studenticscom extends Component {
<div className="ws100s edu-back-white sortinxdirection" style={{
position: "relative"
}}>
<script>
{
`
a{ 
    text-decoration:none;
    color:#333;
}
a:hover{
    text-decoration:none;//鼠标放上面不显示下划线
    color:#333;
}
`
}
</script>
<div className="ws100s teacherentrydivss ">
<div className="ws100s sortinxdirection">
<p className="sortinxdirection h40s" onClick={()=>this.props.statisticsy(false)} >

@ -252,6 +252,20 @@ class Studentstatistics extends Component {
return (
<React.Fragment>
<div className="ws100s mt20">
<script>
{
`
a{ 
    text-decoration:none;
    color:#333;
}
a:hover{
    text-decoration:none;//鼠标放上面不显示下划线
    color:#333;
}
`
}
</script>
<div className="ws100s edu-back-white">
<div className="ws100s teacherentrydivss pd15s">
<div className="ws100s sortinxdirection">
@ -286,11 +300,7 @@ class Studentstatistics extends Component {
onChange={this.table1handleChange}
/>
</Spin>:
<div style={{
minHeight: "400px",
}} className="ws100s">
<NoneDatas></NoneDatas>
</div>
""
}

@ -33,6 +33,20 @@ class Videostatisticscom extends Component {
<div className="ws100s edu-back-white sortinxdirection" style={{
position: "relative"
}}>
<script>
{
`
a{ 
    text-decoration:none;
    color:#333;
}
a:hover{
    text-decoration:none;//鼠标放上面不显示下划线
    color:#333;
}
`
}
</script>
<div className="ws100s teacherentrydivss ">
<div className="ws100s sortinxdirection">
<p className="sortinxdirection h40s" onClick={()=>this.props.statisticsy(false)} >

@ -28,7 +28,7 @@ class Videostatisticscomtwo extends Component {
className: 'font-14',
width: '50px',
render: (text, record) => (
<span style={{width: '50px'}}>{record.number}</span>
<div style={{width: '50px'}}>{record.number}</div>
),
},
{
@ -39,56 +39,56 @@ class Videostatisticscomtwo extends Component {
className: 'font-14 maxnamewidth100s',
width: '100px',
render: (text, record) => (
<span style={{width: '100px'}} className="maxnamewidth100s">
<div style={{width: "100px",wordWrap: 'break-word', wordBreak: 'break-word'}} className="maxnamewidth100s">
<a className="maxnamewidth100s" style={{
color:"#333333"
}} title={record.user_name}>{record.user_name}</a>
</span>
</div>
),
},
{
title: '视频是否看完',
title: '是否看完',
dataIndex: 'is_finished',
key: 'is_finished',
align: "center",
className: 'font-14',
className: 'font-14 maxnamewidth90s',
width: '90px',
render: (text, record) => (
<span style={{width: '90px'}}>{record.is_finished === true ?
<span style={{color: "#5091FF"}}></span> : <span style={{color: "#E02020"}}></span>}</span>
<div style={{width: '90px'}} className="maxnamewidth90s">{record.is_finished === true ?
<span style={{color: "#5091FF"}}></span> : <span style={{color: "#E02020"}}></span>}</div>
),
},
{
title: '视频累计观看时长',
title: '观看时长',
dataIndex: 'total_duration',
key: 'total_duration',
align: "center",
className: 'font-14 maxnamewidth140s',
width: '140px',
className: 'font-14 maxnamewidth100s',
width: '100px',
sorter: true,
sortDirections: sortDirections,
render: (text, record) => (
<span style={{width: '140px'}} className="maxnamewidth140s"><a className="maxnamewidth140s" style={{
<div style={{width: '100px'}} className="maxnamewidth100s"><a className="maxnamewidth100s" style={{
color:"#333333"
}} title={record.total_duration}>{record.total_duration}</a></span>
}} title={record.total_duration}>{record.total_duration}</a></div>
),
},
{
title: '累计观看次数(次)',
title: '观看次数',
dataIndex: 'feq',
key: 'feq',
align: "center",
className: 'font-14 maxnamewidth140s',
width: '140px',
className: 'font-14 maxnamewidth100s',
width: '100px',
sorter: true,
sortDirections: sortDirections,
render: (text, record) => (
<span style={{width: '140px'}} className="maxnamewidth140s">
<a className="maxnamewidth140s" style={{
<div style={{width: '100px'}} className="maxnamewidth100s">
<a className="maxnamewidth100s" style={{
color:"#333333"
}} title={record.feq}>{record.feq}</a>
</span>
</div>
),
},
{
@ -96,14 +96,13 @@ class Videostatisticscomtwo extends Component {
dataIndex: 'start_at',
key: 'start_at',
align: "center",
className: 'font-14 maxnamewidth90s',
width: '90px',
className: 'font-14 ',
render: (text, record) => (
<span style={{width: '90px'}} >
<a className="maxnamewidth90s" style={{
<div>
<a style={{
color:"#333333"
}} title= {moment(record.start_at).format('YYYY-MM-DD HH:mm:ss')}> {record.start_at}</a>
</span>
}} title={moment(record.start_at).format('YYYY-MM-DD HH:mm:ss')}> {moment(record.start_at).format('YYYY-MM-DD HH:mm:ss')}</a>
</div>
),
},
{
@ -111,14 +110,13 @@ class Videostatisticscomtwo extends Component {
dataIndex: 'end_at',
key: 'end_at',
align: "center",
className: 'font-14 maxnamewidth90s',
width: '90px',
className: 'font-14 ',
render: (text, record) => (
<span style={{width: '90px'}} >
<a className="maxnamewidth90s" style={{
<div>
<a style={{
color:"#333333"
}} title={moment(record.end_at).format('YYYY-MM-DD HH:mm:ss')}>{record.end_at}</a>
</span>
}} title={moment(record.end_at).format('YYYY-MM-DD HH:mm:ss')}>{moment(record.end_at).format('YYYY-MM-DD HH:mm:ss')}</a>
</div>
),
}
],
@ -476,20 +474,39 @@ class Videostatisticscomtwo extends Component {
return (
<React.Fragment>
<div className="ws100s">
<script>
{
`
a{ 
    text-decoration:none;
    color:#333;
}
a:hover{
    text-decoration:none;//鼠标放上面不显示下划线
    color:#333;
}
`
}
</script>
<div className="ws100s teacherentrydivss edu-back-white ">
<div className="ws100s sortinxdirection">
<div className="ws50s sptits font-18">{mytitle}</div>
<p className="sortinxdirection h40s" onClick={() => this.props.tisticsbools(false, null)} >
<i className="iconfont icon-zuojiantou1 font-14 posiivsiconmyss mr5 colorbluesigin xiaoshou h36s" style={{color:'#BBBBBB'}} ></i>
</p>
<div className="ws50s sptits font-18">
<div className="ml10">{mytitle}</div>
</div>
<div className="ws50s sptitss xaxisreverseorder font-14" style={{
color: "#5091FF",
lineHeight: "42px",
}}>
{
isAdmin === true ?
<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>
:""
}
{/*{*/}
{/* isAdmin === true ?*/}
{/* <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>*/}
{/* :""*/}
{/*}*/}
{
isAdmin === true ?

@ -249,6 +249,20 @@ class Videostatisticslist extends Component {
return (
<React.Fragment>
<div className="ws100s mt20">
<script>
{
`
a{ 
    text-decoration:none;
    color:#333;
}
a:hover{
    text-decoration:none;//鼠标放上面不显示下划线
    color:#333;
}
`
}
</script>
<div className="ws100s edu-back-white">
<div className="ws100s teacherentrydivss pd15s">
<div className="ws100s sortinxdirection">
@ -285,11 +299,7 @@ class Videostatisticslist extends Component {
/>
</Spin>
:
<div style={{
minHeight: "400px",
}} className="ws100s">
<NoneDatas></NoneDatas>
</div>
""
}

@ -21,7 +21,7 @@ const clipboardMap = {}
function VideoInReviewItem (props) {
const theme = useContext(ThemeContext);
const { history, file_url , play_url , cover_url , transcoded , title, created_at, published_at, isReview, id
, onEditVideo, onMaskClick, getCopyText, showNotification,vv,play_duration,operation , deleteVideo , moveVideo ,link, people_num,total_time} = props;
, onEditVideo, onMaskClick, getCopyText, showNotification,vv,play_duration,operation , deleteVideo , moveVideo ,link, people_num,total_time,Setmyktid} = props;
useEffect(()=> {
if (!isReview) {
_clipboard = new ClipboardJS(`.copybtn_item_${id}`);
@ -38,7 +38,7 @@ function VideoInReviewItem (props) {
}
}, [])
const username = props.match.params.username
function toList() {
@ -52,11 +52,11 @@ function VideoInReviewItem (props) {
<div className={`${isReview ? 'videoInReviewItem' : 'nItem'} videoItem`}>
<Spin tip="正在转码,请稍等..." spinning={!transcoded && !link}>
<img className="cover" src={imgUrl} alt=""></img>
{ link ?
{ link ?
<a href={link} target='_blank' className="otherLinkPanel">
<span className="otherLink">外链</span>
</a>
: ""
</a>
: ""
}
{!isReview && <div className="mask" onClick={() => onMaskClick(props)}></div>}
@ -76,7 +76,7 @@ function VideoInReviewItem (props) {
{/* <span className="time">{moment(published_at || created_at).format('YYYY-MM-DD HH:mm:ss')}{people_num}</span> */}
{link||total_time===undefined?<span className="time"> </span>:<span className="time">{
formatSeconds(total_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>
@ -85,28 +85,38 @@ function VideoInReviewItem (props) {
<span className={"dianjilianicon"}>
{total_time===undefined?'':!people_num || (people_num && people_num)===0 ? "" : <Tooltip title="观看人数" placement="bottom">
<i className={`icon-dianjiliang iconfont dianjilianicon font-12`}> {!people_num || (people_num && people_num)===0?"":people_num}</i>
</Tooltip> }
</Tooltip> }
</span>
<div>
{
props&&props.mykt!=undefined?isReview !== true && moveVideo &&
<Tooltip title="统计" placement="bottom">
<i className="icon-tongji1 iconfont font-15" onClick={() => Setmyktid(props.newcourse_video_id,props.newtitle)}
style={{ marginTop: '1px', display: 'inline-block'}}
></i>
</Tooltip>:""
}
{
isReview !== true && moveVideo &&
<Tooltip title="移动到" placement="bottom">
isReview !== true && moveVideo &&
<Tooltip title="移动" placement="bottom">
<i className="icon-yidong iconfont font-15" onClick={() => moveVideo(props)}
style={{ marginTop: '1px', display: 'inline-block'}}
></i>
</Tooltip>
}
{
deleteVideo &&
deleteVideo &&
<Tooltip title="删除" placement="bottom">
<i className="icon-shanchu iconfont" onClick={() => deleteVideo(props)}
style={{ marginTop: '1px', display: 'inline-block'}}
></i>
</Tooltip>
}
{
isReview !== true && operation &&
<Tooltip title="编辑" placement="bottom">
@ -117,12 +127,12 @@ function VideoInReviewItem (props) {
}
{
isReview !== true && !link ?
<Tooltip title="复制视频地址" placement="bottom">
<Tooltip title="复制" placement="bottom">
<i className={`icon-fuzhi iconfont copybtn_item_${id}`} data-clipboard-text={getCopyText((play_url || file_url), cover_url)}></i>
</Tooltip>:""
}
</div>
</div>
</div>
</div>
</div>

Loading…
Cancel
Save