diff --git a/.gitignore b/.gitignore index 12dc596a6..349c0cdc1 100644 --- a/.gitignore +++ b/.gitignore @@ -43,7 +43,7 @@ /public/react/config/stats.json /public/react/stats.json /public/react/.idea/* - +/public/h5build /public/npm-debug.log # avatars diff --git a/app/controllers/live_links_controller.rb b/app/controllers/live_links_controller.rb index fe2de4afe..f5af80ead 100644 --- a/app/controllers/live_links_controller.rb +++ b/app/controllers/live_links_controller.rb @@ -7,17 +7,17 @@ class LiveLinksController < ApplicationController def index lives = @course.live_links - order_str = "on_status desc,id desc" + order_str = "on_status desc, live_time desc" @total_count = lives.size @my_live_id = @course.live_links.find_by(user_id: current_user.id)&.id - order_str = "live_links.id = #{@my_live_id} desc, #{order_str}" if @my_live_id.present? + # order_str = "live_links.id = #{@my_live_id} desc, #{order_str}" if @my_live_id.present? lives = lives.order("#{order_str}") @lives = paginate lives.includes(user: :user_extension) end def create - tip_exception("一个老师只能设置一个直播间") if @course.live_links.where(user_id: current_user.id).exists? - @course.live_links.create!(create_params.merge(user_id: current_user.id)) + on_status = params[:live_time].present? && params[:live_time].to_time <= Time.now ? 1 : 0 + @course.live_links.create!(create_params.merge(user_id: current_user.id, on_status: on_status)) render_ok end @@ -38,7 +38,8 @@ class LiveLinksController < ApplicationController end end else - current_live.update!(create_params) + on_status = params[:live_time].present? && params[:live_time].to_time <= Time.now ? 1 : 0 + current_live.update!(create_params.merge(on_status: on_status)) end render_ok end @@ -51,7 +52,7 @@ class LiveLinksController < ApplicationController private def create_params - params.permit(:url, :description) + params.permit(:url, :description, :course_name, :platform, :live_time, :duration) end def current_live diff --git a/app/controllers/subjects_controller.rb b/app/controllers/subjects_controller.rb index 31bfdb91e..92976e05a 100644 --- a/app/controllers/subjects_controller.rb +++ b/app/controllers/subjects_controller.rb @@ -72,7 +72,7 @@ class SubjectsController < ApplicationController end # 排序 - order_str = reorder == "publish_time" ? "status = 2 desc, publish_time asc" : "updated_at desc" + order_str = (reorder == "publish_time" ? "homepage_show desc, excellent desc, status = 2 desc, publish_time asc" : "homepage_show desc, excellent desc, updated_at desc") @subjects = @subjects.reorder(order_str) end diff --git a/app/decorators/tiding_decorator.rb b/app/decorators/tiding_decorator.rb index 771df3aa2..8d266b7df 100644 --- a/app/decorators/tiding_decorator.rb +++ b/app/decorators/tiding_decorator.rb @@ -322,7 +322,7 @@ module TidingDecorator end def live_link_content - I18n.t(locale_format) % container&.user.try(:show_real_name) + I18n.t(locale_format) % container&.course_name end def student_graduation_topic_content diff --git a/app/models/live_link.rb b/app/models/live_link.rb index 52c1e3657..9b59eb8c1 100644 --- a/app/models/live_link.rb +++ b/app/models/live_link.rb @@ -4,8 +4,12 @@ class LiveLink < ApplicationRecord has_many :tidings, as: :container, dependent: :destroy - validates :url, presence: true, format: { with: CustomRegexp::URL, message: "必须为网址超链接" } + # validates :url, format: { with: CustomRegexp::URL, message: "必须为网址超链接" } validates :description, length: { maximum: 100, too_long: "不能超过100个字符" } + validates :course_name, presence: true + validates :platform, presence: true + # validates :live_time, presence: true + validates :duration, numericality: { only_integer: true, greater_than: 0}, allow_blank: true def op_auth? user == User.current || User.current.admin_or_business? diff --git a/app/services/videos/batch_publish_service.rb b/app/services/videos/batch_publish_service.rb index ce6bdb163..0523097a2 100644 --- a/app/services/videos/batch_publish_service.rb +++ b/app/services/videos/batch_publish_service.rb @@ -25,7 +25,9 @@ class Videos::BatchPublishService < ApplicationService video.title = param[:title].to_s.strip.presence || video.title video.apply_publish - + if param[:course_id].present? + video.status = "published" + end video.save! if param[:course_id].present? diff --git a/app/views/examination_banks/show.json.jbuilder b/app/views/examination_banks/show.json.jbuilder index 2a2da9af9..eed1b2407 100644 --- a/app/views/examination_banks/show.json.jbuilder +++ b/app/views/examination_banks/show.json.jbuilder @@ -40,10 +40,14 @@ json.exam do json.all_questions_count @items.size json.discipline do - json.(@exam.sub_discipline&.discipline, :id, :name) + if @exam.sub_discipline&.discipline.present? + json.(@exam.sub_discipline&.discipline, :id, :name) + end end json.sub_discipline do - json.(@exam.sub_discipline, :id, :name) + if @exam.sub_discipline.present? + json.(@exam.sub_discipline, :id, :name) + end end json.tag_disciplines @exam.tag_disciplines do |tag| json.(tag, :id, :name) diff --git a/app/views/homework_commons/index.json.jbuilder b/app/views/homework_commons/index.json.jbuilder index db3603746..a508659e8 100644 --- a/app/views/homework_commons/index.json.jbuilder +++ b/app/views/homework_commons/index.json.jbuilder @@ -17,7 +17,10 @@ json.homeworks @homework_commons.each do |homework| json.status_time curr_status[:time] json.time_status curr_status[:time_status] json.allow_late homework.allow_late - json.author homework.user.real_name + json.author homework.user&.real_name + json.author_img url_to_avatar(homework.user) + json.author_login homework.user&.login + json.created_at homework.created_at.strftime("%Y-%m-%d") # 只有在主目录才显示 json.upper_category_name homework.course_second_category&.name unless params[:category] diff --git a/app/views/homework_commons/works_list.json.jbuilder b/app/views/homework_commons/works_list.json.jbuilder index f5e6ca01a..cd2f17cf5 100644 --- a/app/views/homework_commons/works_list.json.jbuilder +++ b/app/views/homework_commons/works_list.json.jbuilder @@ -84,6 +84,7 @@ elsif @user_course_identity == Course::STUDENT json.user_login @work.user.login json.student_id @work.user.student_id json.user_name @work.user.real_name + json.user_img url_to_avatar(@work.user) json.group_name @member.course_group_name end @@ -108,6 +109,7 @@ if @homework.homework_type == "practice" json.view_answer_count work.myshixun.try(:view_answer_count).to_i json.user_login work.user.try(:login) json.user_name work.user.try(:real_name) + json.user_img url_to_avatar(work.user) json.student_id work.user.try(:student_id) json.group_name @students.select{|student| student.user_id == work.user_id}.first.try(:course_group_name) json.work_status work.compelete_status @@ -169,6 +171,7 @@ elsif @homework.homework_type == "group" || @homework.homework_type == "normal" json.user_login @is_evaluation ? "--" : work.user.try(:login) json.user_name @is_evaluation ? "匿名" : work.user.try(:real_name) + json.user_img url_to_avatar(@is_evaluation ? "0" : work.user) end end diff --git a/app/views/live_links/edit.json.jbuilder b/app/views/live_links/edit.json.jbuilder index 047a226e8..6b0fd385d 100644 --- a/app/views/live_links/edit.json.jbuilder +++ b/app/views/live_links/edit.json.jbuilder @@ -1 +1 @@ -json.(@live, :id, :description, :url) +json.(@live, :id, :description, :url, :platform, :live_time, :duration, :course_name) diff --git a/app/views/live_links/index.json.jbuilder b/app/views/live_links/index.json.jbuilder index e497a068b..95891fc8a 100644 --- a/app/views/live_links/index.json.jbuilder +++ b/app/views/live_links/index.json.jbuilder @@ -1,12 +1,12 @@ json.lives @lives do |live| - json.(live, :id, :description, :on_status) + json.(live, :id, :description, :on_status, :duration, :course_name, :platform) json.url live.on_status ? live.url : "" json.author_name live.user.show_real_name json.author_login live.user.login json.author_img url_to_avatar(live.user) json.op_auth live.op_auth? json.delete_auth live.delete_auth? - json.created_at live.created_at.strftime('%Y-%m-%d') + json.live_time live.live_time&.strftime('%Y-%m-%d %H:%M:%S') end json.my_live_id @my_live_id json.total_count @total_count \ No newline at end of file diff --git a/config/locales/tidings/zh-CN.yml b/config/locales/tidings/zh-CN.yml index 92c815a05..cda146780 100644 --- a/config/locales/tidings/zh-CN.yml +++ b/config/locales/tidings/zh-CN.yml @@ -238,4 +238,4 @@ 2_end: "你提交的发布视频申请:%s,审核未通过
原因:%{reason}" PublicCourseStart_end: "你报名参与的开放课程:%s,将于%s正式开课" SubjectStartCourse_end: "您创建的开放课程:%s 已达到开课人数要求。您可以在24小时内自主开设新一期课程。如果超过24小时未开课,平台将自动开课并复制您上一期的课程内容。" - LiveLink_end: "%s老师正在直播中" + LiveLink_end: "%s 直播将于30分钟后开始" diff --git a/config/locales/zh-CN.yml b/config/locales/zh-CN.yml index 6900f6c51..4f41df0c5 100644 --- a/config/locales/zh-CN.yml +++ b/config/locales/zh-CN.yml @@ -173,7 +173,10 @@ zh-CN: live_link: description: '说明' url: '链接' - + course_name: '课程名称' + platform: '直播平台' + live_time: '开播时间' + duration: '直播时长' diff --git a/db/migrate/20200212072045_add_columns_to_live_links.rb b/db/migrate/20200212072045_add_columns_to_live_links.rb new file mode 100644 index 000000000..e0c59dcfa --- /dev/null +++ b/db/migrate/20200212072045_add_columns_to_live_links.rb @@ -0,0 +1,8 @@ +class AddColumnsToLiveLinks < ActiveRecord::Migration[5.2] + def change + add_column :live_links, :course_name, :string + add_column :live_links, :platform, :string + add_column :live_links, :live_time, :datetime + add_column :live_links, :duration, :integer + end +end diff --git a/db/migrate/20200213094050_migrate_user_location.rb b/db/migrate/20200213094050_migrate_user_location.rb new file mode 100644 index 000000000..a15d299a1 --- /dev/null +++ b/db/migrate/20200213094050_migrate_user_location.rb @@ -0,0 +1,11 @@ +class MigrateUserLocation < ActiveRecord::Migration[5.2] + def change + UserExtension.where("location like '%省'").each do |ue| + ue.update_column("location", ue.location.chop) + end + + UserExtension.where("location_city like '%市'").each do |ue| + ue.update_column("location_city", ue.location_city.chop) + end + end +end diff --git a/lib/tasks/live_notice.rake b/lib/tasks/live_notice.rake new file mode 100644 index 000000000..da57ebd4b --- /dev/null +++ b/lib/tasks/live_notice.rake @@ -0,0 +1,13 @@ +namespace :live_notice do + desc "send a live message to students before 30 minutes" + task message: :environment do + lives = LiveLink.where(on_status: 0).where("live_time <= '#{Time.now + 30*60}' and live_time > '#{Time.now}'") + lives.each do |live| + LivePublishJob.perform_later(live.id) + end + end + + task on_status: :environment do + LiveLink.where(on_status: 0).where("live_time <= '#{Time.now}'").update_all(on_status: 1) + end +end \ No newline at end of file diff --git a/public/react/src/modules/courses/Video/LiveItem.js b/public/react/src/modules/courses/Video/LiveItem.js index a2fff5b98..85cc05bc0 100644 --- a/public/react/src/modules/courses/Video/LiveItem.js +++ b/public/react/src/modules/courses/Video/LiveItem.js @@ -1,25 +1,17 @@ import React,{ Component } from "react"; -import { Switch } from 'antd'; import { getImageUrl } from 'educoder'; +import { Modal } from 'antd'; import { WordsBtn } from 'educoder'; import axios from 'axios'; class LiveItem extends Component{ - - changeStatus=(flag,event,id)=>{ - const url = `/live_links/${id}.json`; - axios.put(url,{ - on_status:flag?1:0 - }).then(result=>{ - if(result){ - this.props.showNotification(`直播已${flag?"开启":"关闭"}!`); - const { successFunc } = this.props; - successFunc && successFunc(1); - } - }).catch(error=>{ - console.log(error); - }) + constructor(props) { + super(props); + this.state = { + visible:false + } } + deleteLive=(id)=>{ this.props.confirm({ content: '是否确认删除?', @@ -40,39 +32,87 @@ class LiveItem extends Component{ console.log('Cancel'); }, }); + } + alertInfo=()=>{ + console.log("dddd"); + this.setState({ + visible:true + }) + } + onDialogOkBtnClick=()=>{ + this.setState({ + visible:false, + }) } render(){ const { key, item , setLiveId } = this.props; - // let flag = false; - // flag = item.on_status; + const { visible } = this.state; return(
+ +
+

直播链接失效

+
+
+ 知道了 +
+
+ { + visible ? + + : + "" + }
- {`${item.author_name}`} - + {item.course_name} {item.on_status?'已开播':'未开播'} - { - item.op_auth ? - this.changeStatus(flag,event,item.id)}>:"" - }

{item.description}

{ - item.on_status? - 进入 + item.on_status ? + + { + item.url ? + 进入 + : + 进入 + } + : 进入 }

- 创建时间:{item.created_at} - + + {`${item.author_name}`} + + { item.platform && 直播平台:{item.platform} } + { item.live_time && 开播时间:{item.live_time}} + { item.duration && 直播时长:{item.duration} } + { item.op_auth ? @@ -80,7 +120,7 @@ class LiveItem extends Component{ } { item.delete_auth ? - this.deleteLive(item.id)}>删除 + this.deleteLive(item.id)}>删除 :"" } diff --git a/public/react/src/modules/courses/Video/LiveNew.js b/public/react/src/modules/courses/Video/LiveNew.js index 2cd23f049..0961d0ef7 100644 --- a/public/react/src/modules/courses/Video/LiveNew.js +++ b/public/react/src/modules/courses/Video/LiveNew.js @@ -1,19 +1,48 @@ import React,{ Component } from "react"; -import { Modal , Form , Input , Spin } from 'antd'; +import { Modal , Form , Input , Spin , Select , AutoComplete , DatePicker , InputNumber } from 'antd'; +import locale from 'antd/lib/date-picker/locale/zh_CN'; +import moment from 'moment'; +import { handleDateString } from 'educoder'; import './video.css'; import axios from 'axios'; + const { TextArea } = Input; +const { Option } = Select; +// ,'威佰通' +const array=['腾讯课堂','B站','斗鱼']; + +function range(start, end) { + const result = []; + for (let i = start; i < end; i++) { + result.push(i); + } + return result; +} +function disabledDateTime() { + return { + disabledMinutes: () => range(1, 30).concat(range(31, 60)), + }; +} +function disabledDate(current) { + return current && current < moment().endOf('day').subtract(1, 'days'); +} + class LiveNew extends Component{ constructor(props){ super(props); this.state={ - isSpining:false + isSpining:false, + beginTime:undefined, } } + componentDidMount=()=>{ + this.checkType(); + } + componentDidUpdate=(prevState)=>{ if(prevState && prevState.liveId !== this.props.liveId){ this.setState({ @@ -25,7 +54,7 @@ class LiveNew extends Component{ checkType=()=>{ const { liveId } = this.props; - + this.clearAll(); if(liveId){ const url =`/live_links/${liveId}/edit.json`; axios.get(url).then(result=>{ @@ -33,14 +62,15 @@ class LiveNew extends Component{ this.props.form.setFieldsValue({ url:result.data.url, description:result.data.description, + platform:result.data.platform || "腾讯课堂", + duration:result.data.duration, + course_name:result.data.course_name + }) + this.setState({ + beginTime:result.data.live_time && moment(result.data.live_time,"YYYY-MM-DD HH:mm") }) } }) - }else{ - this.props.form.setFieldsValue({ - url:undefined, - description:undefined - }) } this.setState({ isSpining:false @@ -50,7 +80,9 @@ class LiveNew extends Component{ handleSubmit=()=>{ this.props.form.validateFields((err, values) => { if(!err){ - console.log("2") + this.setState({ + isSpining:true + }) const { liveId } = this.props; if(liveId){ // 修改 @@ -64,15 +96,23 @@ class LiveNew extends Component{ // 修改 updateFunc=(id,values)=>{ const url = `/live_links/${id}.json`; + const { beginTime } = this.state; axios.put(url,{ - ...values + ...values, + live_time:beginTime }).then(result=>{ if(result){ this.props.showNotification("修改成功!"); const { setliveVisibel } = this.props; setliveVisibel && setliveVisibel(false,true); } + this.setState({ + isSpining:false + }) }).catch(error=>{ + this.setState({ + isSpining:false + }) console.log(error); }) } @@ -81,15 +121,23 @@ class LiveNew extends Component{ creatFunc=(values)=>{ const CourseId=this.props.match.params.coursesId; const url = `/courses/${CourseId}/live_links.json`; + const { beginTime } = this.state; axios.post(url,{ - ...values + ...values, + live_time:beginTime }).then(result=>{ if(result){ this.props.showNotification("添加成功!"); const { setliveVisibel } = this.props; setliveVisibel && setliveVisibel(false,true); } + this.setState({ + isSpining:false + }) }).catch(error=>{ + this.setState({ + isSpining:false + }) console.log(error); }) } @@ -107,23 +155,44 @@ class LiveNew extends Component{ cancelNew=()=>{ const { setliveVisibel } = this.props; + this.clearAll(); + setliveVisibel && setliveVisibel(false); + } + + clearAll=()=>{ this.props.form.setFieldsValue({ + course_name:undefined, + platform:"腾讯课堂", url:undefined, - description:undefined + description:undefined, + duration:undefined + }) + this.setState({ + beginTime:undefined + }) + } + + onChangeTime=(data,dateString)=>{ + this.setState({ + beginTime:handleDateString(dateString) }) - setliveVisibel && setliveVisibel(false); } render(){ - const { isSpining } = this.state; + const { isSpining , beginTime } = this.state; const {getFieldDecorator} = this.props.form; const { visible } = this.props; + const dataSource = array.map((item,key)=>{ + return( + + ) + }) return(

+ + {getFieldDecorator('course_name', { + rules: [{required: true, message: "请输入课程名称"}], + })( + + )} + + + {getFieldDecorator('platform', { + rules: [{required: true, message: "请选择直播平台"}], + })( + + + )} + {getFieldDecorator('url', { - rules: [{required: true, message: "请输入第三方直播链接"}], + rules: [], })( )} +
+
+

开播时间

+ +
+ + {getFieldDecorator('duration', { + rules: [], + })( + + )} + + 分钟 +
{getFieldDecorator('description', { rules: [{ @@ -147,10 +261,7 @@ class LiveNew extends Component{