From dc01f2630b34bf51e58e6da2bdc627aa88fff87d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=98=8E?= <775174143@qq.com>
Date: Tue, 24 Dec 2019 13:59:05 +0800
Subject: [PATCH 01/25] =?UTF-8?q?=E8=B0=83=E6=95=B4=E6=97=B6=E9=97=B4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../react/src/modules/courses/exercise/Exercisesetting.js   | 2 +-
 public/react/src/modules/courses/poll/PollDetailTabForth.js | 6 ++++++
 .../src/modules/courses/poll/PollDetailTabForthRules.js     | 2 +-
 3 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/public/react/src/modules/courses/exercise/Exercisesetting.js b/public/react/src/modules/courses/exercise/Exercisesetting.js
index 87d05255c..df4167047 100644
--- a/public/react/src/modules/courses/exercise/Exercisesetting.js
+++ b/public/react/src/modules/courses/exercise/Exercisesetting.js
@@ -525,7 +525,7 @@ class Exercisesetting extends Component{
                 end_time:null
             })
         }else{
-            if(moment(date,"YYYY-MM-DD HH:mm") <= moment()){
+            if(dateString<moment().format('YYYY-MM-DD HH:mm')){
                 this.setState({
                     unit_e_tip:"截止时间不能早于当前时间",
                     e_flag:true
diff --git a/public/react/src/modules/courses/poll/PollDetailTabForth.js b/public/react/src/modules/courses/poll/PollDetailTabForth.js
index e5cbfdce7..e2456d6d9 100644
--- a/public/react/src/modules/courses/poll/PollDetailTabForth.js
+++ b/public/react/src/modules/courses/poll/PollDetailTabForth.js
@@ -33,6 +33,11 @@ function disabledDateTime() {
 		// disabledSeconds: () => [55, 56],
 	};
 }
+
+function disabledDate(current) {
+	return current && current < moment().endOf('day').subtract(1, 'days');
+}
+
 const dataformat="YYYY-MM-DD HH:mm";
 
 class PollDetailTabForth extends Component{
@@ -597,6 +602,7 @@ class PollDetailTabForth extends Component{
 																width={"240px"}
 																format="YYYY-MM-DD HH:mm"
 																disabledTime={disabledDateTime}
+																disabledDate={disabledDate}
 																onChange={this.onChangeTimeEnd}
 																value={ end_time && moment(end_time,dataformat) }
 																disabled={un_change_end == true ? this.props.isAdmin()?!flagPageEdit:true : !flagPageEdit }
diff --git a/public/react/src/modules/courses/poll/PollDetailTabForthRules.js b/public/react/src/modules/courses/poll/PollDetailTabForthRules.js
index c531d20b7..39176752b 100644
--- a/public/react/src/modules/courses/poll/PollDetailTabForthRules.js
+++ b/public/react/src/modules/courses/poll/PollDetailTabForthRules.js
@@ -447,7 +447,7 @@ class PollDetailTabForthRules extends Component{
                 </p>
               </div>
               <div className="fl mr20 yskspickersy">
-                <Tooltip placement="bottom" title={rule.e_timeflag ? this.props.isAdmin()?"截止时间已过,不能再修改":"":""}>
+                <Tooltip placement="bottom" title={rule.e_timeflag ? this.props.isAdmin()?"":"截止时间已过,不能再修改":""}>
                   <span>
                     <DatePicker
 											showToday={false}

From 0c4a92251ec344e54de909470c8601ab80ec17ed Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=98=8E?= <775174143@qq.com>
Date: Tue, 24 Dec 2019 14:32:07 +0800
Subject: [PATCH 02/25] =?UTF-8?q?=E8=B0=83=E6=95=B4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../courses/exercise/Exercisesetting.js       | 19 ++++++-------------
 .../modules/courses/graduation/tasks/index.js |  2 +-
 .../courses/poll/PollDetailTabForth.js        |  4 ++--
 .../courses/poll/PollDetailTabForthRules.js   |  2 +-
 4 files changed, 10 insertions(+), 17 deletions(-)

diff --git a/public/react/src/modules/courses/exercise/Exercisesetting.js b/public/react/src/modules/courses/exercise/Exercisesetting.js
index df4167047..654da480c 100644
--- a/public/react/src/modules/courses/exercise/Exercisesetting.js
+++ b/public/react/src/modules/courses/exercise/Exercisesetting.js
@@ -178,16 +178,9 @@ class Exercisesetting extends Component{
 
                 }
                 if(result.data.exercise.unified_setting == true && moment(result.data.exercise.end_time) <= moment()){
-
-                    // if(this.props.isSuperAdmin()===true){
-                    //     this.setState({
-                    //         end_timetype:false
-                    //     })
-                    // }else{
                         this.setState({
                             end_timetype:true
                         })
-                    // }
                 }
 
                 let group=result.data.published_course_groups;
@@ -236,10 +229,10 @@ class Exercisesetting extends Component{
 //提交form表单
     handleSubmit = (e) => {
         e.preventDefault();
-         if(this.props&&this.props.Commonheadofthetestpaper.exercise_status){
-             console.log("190");
-             console.log(this.props.Commonheadofthetestpaper.exercise_status);
-         }
+         // if(this.props&&this.props.Commonheadofthetestpaper.exercise_status){
+         //     console.log("190");
+         //     console.log(this.props.Commonheadofthetestpaper.exercise_status);
+         // }
 
         this.props.form.validateFieldsAndScroll((err, values) => {
             if(!err){
@@ -327,7 +320,7 @@ class Exercisesetting extends Component{
                 }
             }
 
-             if(this.state.end_timetype === false){
+             if(this.state.end_timetype === false||this.props.isAdmin()==true){
                  if(moment(end_time,dataformat) <= moment(publish_time,dataformat)){
                      this.setState({
                          unit_e_tip:"截止时间不能小于发布时间"
@@ -525,7 +518,7 @@ class Exercisesetting extends Component{
                 end_time:null
             })
         }else{
-            if(dateString<moment().format('YYYY-MM-DD HH:mm')){
+            if(dateString<=moment().format('YYYY-MM-DD HH:mm')){
                 this.setState({
                     unit_e_tip:"截止时间不能早于当前时间",
                     e_flag:true
diff --git a/public/react/src/modules/courses/graduation/tasks/index.js b/public/react/src/modules/courses/graduation/tasks/index.js
index e58281ee4..c316035ee 100644
--- a/public/react/src/modules/courses/graduation/tasks/index.js
+++ b/public/react/src/modules/courses/graduation/tasks/index.js
@@ -666,7 +666,7 @@ class GraduationTasks extends Component{
             <React.Fragment>
               {/*{this.props.isAdmin() ?<WordsBtn style="blue" className="mr30" onClick={() => this.addDir()}>题库选用</WordsBtn>:""}*/}
               {/*{this.props.isAdmin() ?<a href={"/api/graduation_tasks/"+category_id+"/tasks_list.xls"} className={"fr color-blue font-16"}>导出成绩</a> :""}*/}
-              {this.props.isAdmin() ? <WordsBtn style="blue" className="mr10 fr font-16">
+              {this.props.isAdmin() ? <WordsBtn style="blue" className=" fr font-16">
                 <Link to={"/courses/" + coursesId + "/graduation_tasks/"+category_id+"/new"}>
                   <span className={"color-blue font-16"}>新建</span>
                 </Link>
diff --git a/public/react/src/modules/courses/poll/PollDetailTabForth.js b/public/react/src/modules/courses/poll/PollDetailTabForth.js
index e2456d6d9..98127be7e 100644
--- a/public/react/src/modules/courses/poll/PollDetailTabForth.js
+++ b/public/react/src/modules/courses/poll/PollDetailTabForth.js
@@ -589,7 +589,7 @@ class PollDetailTabForth extends Component{
 											<div className="clearfix">
 												<span className="mr15 fl mt10 font-16">截止时间:</span>
 												<div className="fl">
-													<Tooltip placement="bottom" title={un_change_end ? this.props.isAdmin()?"":"截止时间已过,不能再修改":""}>
+													<Tooltip placement="bottom" title={un_change_end ? this.props.isAdmin()?"截止时间已过,不能再修改":"":""}>
 														<span>
 															<DatePicker
 																showToday={false}
@@ -605,7 +605,7 @@ class PollDetailTabForth extends Component{
 																disabledDate={disabledDate}
 																onChange={this.onChangeTimeEnd}
 																value={ end_time && moment(end_time,dataformat) }
-																disabled={un_change_end == true ? this.props.isAdmin()?!flagPageEdit:true : !flagPageEdit }
+																disabled={un_change_end == true ?true : !flagPageEdit }
 															>
 															</DatePicker>
 														</span>
diff --git a/public/react/src/modules/courses/poll/PollDetailTabForthRules.js b/public/react/src/modules/courses/poll/PollDetailTabForthRules.js
index 39176752b..1a53b1acd 100644
--- a/public/react/src/modules/courses/poll/PollDetailTabForthRules.js
+++ b/public/react/src/modules/courses/poll/PollDetailTabForthRules.js
@@ -462,7 +462,7 @@ class PollDetailTabForthRules extends Component{
 											disabledTime={disabledDateTime}
 											disabledDate={disabledDate}
 											disabled={
-											  this.props.type==="polls"||this.props.type==="Exercise"?
+										    this.props.type==="Exercise"?
 											  rule.e_timeflag === undefined ? rule.publish_time === null ? false : moment(rule.end_time, dataformat) <= moment() ?this.props.isAdmin()?!flagPageEdit: true : !flagPageEdit : rule.e_timeflag == true ? this.props.isAdmin()?!flagPageEdit :true : !flagPageEdit:
                           rule.e_timeflag === undefined ? rule.publish_time === null ? false : moment(rule.end_time, dataformat) <= moment() ? true : !flagPageEdit : rule.e_timeflag == true ? true : !flagPageEdit
                       }

From 4c7bc229652d8f0562fce3443616af74742b617c Mon Sep 17 00:00:00 2001
From: daiao <358551898@qq.com>
Date: Tue, 24 Dec 2019 15:18:48 +0800
Subject: [PATCH 03/25] =?UTF-8?q?=E8=AF=84=E8=AE=BA?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 app/controllers/comments_controller.rb |  1 +
 app/controllers/hacks_controller.rb    |  8 ++++++++
 app/models/discuss.rb                  | 19 +++++++++++--------
 app/models/hack.rb                     | 12 ++++++++++++
 app/models/praise_tread.rb             |  2 +-
 config/routes.rb                       |  2 ++
 6 files changed, 35 insertions(+), 9 deletions(-)

diff --git a/app/controllers/comments_controller.rb b/app/controllers/comments_controller.rb
index 72afb3342..ddce9a630 100644
--- a/app/controllers/comments_controller.rb
+++ b/app/controllers/comments_controller.rb
@@ -46,6 +46,7 @@ class CommentsController < ApplicationController
   # 隐藏、取消隐藏
   def hidden
     if @hack.manager?(current_user)
+      @discuss = @hack.discusses.where(id: params[:id]).first
       @discuss.update_attribute(:hidden, params[:hidden] == "1")
       sucess_status
     else
diff --git a/app/controllers/hacks_controller.rb b/app/controllers/hacks_controller.rb
index b7f6a30a2..7a0fb7635 100644
--- a/app/controllers/hacks_controller.rb
+++ b/app/controllers/hacks_controller.rb
@@ -98,12 +98,20 @@ class HacksController < ApplicationController
   # 发布功能
   def publish
     @hack.update_attribute(:status, 1)
+    base_attrs = {
+        trigger_user_id: current_user.id, viewed: 0, tiding_type: 'System', user_id: @hack.user_id,
+    }
+    @hack.tidings.create!(base_attrs)
     render_ok
   end
 
   # 取消发布
   def cancel_publish
     @hack.update_attribute(:status, 0)
+    base_attrs = {
+        trigger_user_id: current_user.id, viewed: 0, tiding_type: 'System', user_id: @hack.user_id
+    }
+    @hack.tidings.create!(base_attrs)
     render_ok
   end
 
diff --git a/app/models/discuss.rb b/app/models/discuss.rb
index 652ffea37..148d6518b 100644
--- a/app/models/discuss.rb
+++ b/app/models/discuss.rb
@@ -52,16 +52,19 @@ class Discuss < ApplicationRecord
   private
 
   def send_tiding
+    if dis_type == 'Shixun'
+      user_id = has_parent? ? parent.user_id : Challenge.find(challenge_id).user_id
+      parent_container_type = 'Challenge'
+      challenge_id = challenge_id
+    elsif dis_type == 'Hack'
+      user_id = has_parent? ? parent.user_id : Hack.find(dis_id).user_id
+      parent_container_type = 'Hack'
+      challenge_id = nil
+    end
     base_attrs = {
-      trigger_user_id: user_id, parent_container_id: challenge_id, parent_container_type: 'Challenge',
-      belong_container_id: dis_id, belong_container_type: dis_type, viewed: 0, tiding_type: 'Comment'
+        trigger_user_id: user_id, parent_container_id: challenge_id, parent_container_type: parent_container_type,
+        belong_container_id: dis_id, belong_container_type: dis_type, viewed: 0, tiding_type: 'Comment'
     }
-    user_id =
-        if dis_type == 'Shixun'
-          has_parent? ? parent.user_id : Challenge.find(challenge_id).user_id
-        elsif dis_type == 'Hack'
-          has_parent? ? parent.user_id : Hack.find(dis_id).user_id
-        end
     tidings.create!(base_attrs.merge(user_id: user_id))
   end
 end
diff --git a/app/models/hack.rb b/app/models/hack.rb
index 2e2ffb9e0..35abb8787 100644
--- a/app/models/hack.rb
+++ b/app/models/hack.rb
@@ -13,6 +13,8 @@ class Hack < ApplicationRecord
   has_many :discusses, as: :dis, dependent: :destroy
   # 点赞
   has_many :praise_treads, as: :praise_tread_object, dependent: :destroy
+  # 消息
+  has_many :tidings, as: :container, dependent: :destroy
 
   belongs_to :user
 
@@ -21,6 +23,8 @@ class Hack < ApplicationRecord
   scope :opening, -> {where(open_or_not: 1)}
   scope :mine, -> (author_id){ where(user_id: author_id) }
 
+  after_destroy :send_delete_tiding
+
   def language
     if hack_codes.count == 1
       hack_codes.first.language
@@ -49,4 +53,12 @@ class Hack < ApplicationRecord
     user_id == user.id || user.admin_or_business?
   end
 
+  private
+  def send_delete_tiding
+    base_attrs = {
+        user_id: user_id, viewed: 0, tiding_type: 'Delete', trigger_user_id: current_user.id
+    }
+    tidings.create!(base_attrs)
+  end
+
 end
diff --git a/app/models/praise_tread.rb b/app/models/praise_tread.rb
index 58ec965b4..8e96b7d47 100644
--- a/app/models/praise_tread.rb
+++ b/app/models/praise_tread.rb
@@ -12,7 +12,7 @@ class PraiseTread < ApplicationRecord
     case self.praise_tread_object_type
       when  "Memo","Message","Issue"
         self.tidings << Tiding.new(:trigger_user_id => self.user_id, :user_id => self.praise_tread_object.author_id, :parent_container_id => self.praise_tread_object_id, :parent_container_type => self.praise_tread_object_type, :viewed => 0, :tiding_type => "Praise")
-      when "Discuss","Challenge","HomeworkCommon","JournalsForMessage","Journal","GraduationTopic","GraduationTask"
+      when "Discuss","Challenge","HomeworkCommon","JournalsForMessage","Journal","GraduationTopic","GraduationTask", "Hack"
         self.tidings << Tiding.new(:trigger_user_id => self.user_id, :user_id => self.praise_tread_object.user_id, :parent_container_id => self.praise_tread_object_id, :parent_container_type => self.praise_tread_object_type, :viewed => 0, :tiding_type => "Praise")
     end
   end
diff --git a/config/routes.rb b/config/routes.rb
index ace8324ce..45bd13680 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -71,6 +71,8 @@ Rails.application.routes.draw do
       resources :comments do
         collection do
           post :reply
+        end
+        member do
           post :hidden
         end
       end

From e0ab22b3732da8a91429d0ba18440876874bb99f Mon Sep 17 00:00:00 2001
From: daiao <358551898@qq.com>
Date: Tue, 24 Dec 2019 15:23:19 +0800
Subject: [PATCH 04/25] fixbug

---
 app/views/hack_user_lastest_codes/show.json.jbuilder | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/app/views/hack_user_lastest_codes/show.json.jbuilder b/app/views/hack_user_lastest_codes/show.json.jbuilder
index be700f112..4158f98b2 100644
--- a/app/views/hack_user_lastest_codes/show.json.jbuilder
+++ b/app/views/hack_user_lastest_codes/show.json.jbuilder
@@ -1,5 +1,5 @@
 json.hack do
-  json.(@hack, :name, :difficult, :time_limit, :description, :score, :identifier, :status, :praises_count)
+  json.(@hack, :id, :name, :difficult, :time_limit, :description, :score, :identifier, :status, :praises_count)
   json.language @hack.language
   json.username @hack.user.real_name
   json.code @my_hack.code

From 303f5e4d37850f962f0bd6bc212e00894bc8c63d Mon Sep 17 00:00:00 2001
From: daiao <358551898@qq.com>
Date: Tue, 24 Dec 2019 15:31:35 +0800
Subject: [PATCH 05/25] =?UTF-8?q?=E9=9A=90=E8=97=8F=E8=AF=84=E8=AE=BA?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 app/controllers/comments_controller.rb    | 7 ++++++-
 app/views/comments/_discuss.json.jbuilder | 1 +
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/app/controllers/comments_controller.rb b/app/controllers/comments_controller.rb
index ddce9a630..6451c8734 100644
--- a/app/controllers/comments_controller.rb
+++ b/app/controllers/comments_controller.rb
@@ -32,7 +32,12 @@ class CommentsController < ApplicationController
 
   # 列表
   def index
-    discusses = @hack.discusses.where(root_id: nil)
+    discusses =
+        if current_user.admin_or_business?
+          @hack.discusses.where(root_id: nil)
+        else
+          @hack.discusses.where(root_id: nil, hidden: false)
+        end
     @discusses_count = discusses.count
     @discusses= paginate discusses
   end
diff --git a/app/views/comments/_discuss.json.jbuilder b/app/views/comments/_discuss.json.jbuilder
index b634b20a8..fed402ffa 100644
--- a/app/views/comments/_discuss.json.jbuilder
+++ b/app/views/comments/_discuss.json.jbuilder
@@ -5,6 +5,7 @@ json.id discuss.id
 json.content content_safe(discuss.content)
 json.time time_from_now(discuss.created_at)
 json.hack_id discuss.dis_id
+json.hidden discuss.hidden
 # 主贴和回复有一些不同点
 if discuss.parent_id
   json.can_delete discuss.can_deleted?(current_user)

From addba1de12f1ab8c14ab7d36e1359670279173d5 Mon Sep 17 00:00:00 2001
From: daiao <358551898@qq.com>
Date: Tue, 24 Dec 2019 15:42:37 +0800
Subject: [PATCH 06/25] =?UTF-8?q?=E7=AE=A1=E7=90=86=E5=91=98=E8=BF=90?=
 =?UTF-8?q?=E8=90=A5=E4=BA=BA=E5=91=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 app/controllers/comments_controller.rb               | 2 +-
 app/views/hack_user_lastest_codes/show.json.jbuilder | 1 +
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/app/controllers/comments_controller.rb b/app/controllers/comments_controller.rb
index 6451c8734..c011d53ec 100644
--- a/app/controllers/comments_controller.rb
+++ b/app/controllers/comments_controller.rb
@@ -50,7 +50,7 @@ class CommentsController < ApplicationController
 
   # 隐藏、取消隐藏
   def hidden
-    if @hack.manager?(current_user)
+    if current_user.admin_or_business?
       @discuss = @hack.discusses.where(id: params[:id]).first
       @discuss.update_attribute(:hidden, params[:hidden] == "1")
       sucess_status
diff --git a/app/views/hack_user_lastest_codes/show.json.jbuilder b/app/views/hack_user_lastest_codes/show.json.jbuilder
index 4158f98b2..f3ae49539 100644
--- a/app/views/hack_user_lastest_codes/show.json.jbuilder
+++ b/app/views/hack_user_lastest_codes/show.json.jbuilder
@@ -16,5 +16,6 @@ end
 json.user do
   json.partial! 'users/user', user: current_user
   json.hack_manager @hack.manager?(current_user)
+  json.admin current_user.admin_or_business?
 
 end
\ No newline at end of file

From 48677128d61890a146b78edd63a756015c391701 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=98=8E?= <775174143@qq.com>
Date: Tue, 24 Dec 2019 15:46:28 +0800
Subject: [PATCH 07/25] =?UTF-8?q?=E8=B0=83=E6=95=B4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 public/react/src/modules/page/VNC.css         |  22 ++++++++++++++----
 .../src/modules/page/images/float_switch.jpg  | Bin 1303 -> 1003 bytes
 .../modules/page/images/test/float_switch.jpg | Bin 0 -> 1303 bytes
 .../react/src/modules/tpm/jupyter/index.scss  |   2 +-
 4 files changed, 18 insertions(+), 6 deletions(-)
 create mode 100644 public/react/src/modules/page/images/test/float_switch.jpg

diff --git a/public/react/src/modules/page/VNC.css b/public/react/src/modules/page/VNC.css
index d59d91121..1180baf76 100644
--- a/public/react/src/modules/page/VNC.css
+++ b/public/react/src/modules/page/VNC.css
@@ -1,11 +1,12 @@
 .float_button {
-    background-image: url(./images/float_switch.jpg);
-    height: 112px;
+    background-image: url(images/float_switch.jpg);
+    height: 141px;
     width: 38px;
     position: absolute;
     left: -38px;
     top: 32%;
     cursor: pointer;
+    padding-top: 15px;
 }
 .float_button .text {
     position: relative;
@@ -17,8 +18,8 @@
 }
 
 .jupyter_float_button {
-    background-image: url(./images/float_switch.jpg);
-    height: 112px;
+    background-image: url(images/float_switch.jpg);
+    height: 141px;
     width: 38px;
     position: absolute;
     right: 0px;
@@ -26,6 +27,7 @@
     cursor: pointer;
     left:auto;
     z-index: 99999999;
+    padding-top: 15px;
 }
 
 .jupyter_float_button .text {
@@ -37,6 +39,16 @@
     user-select: none;
 }
 
+@keyframes mymove
+{
+    from {right:0px;}
+    to {right:330px;}
+}
+
 .newjupyter_float_button{
-    right: 330px;
+    /*right: 330px;*/
+    /*animation-duration:2s;*/
+    /*infinite*/
+    animation:mymove 0.35s;
+    animation-fill-mode:forwards;
 }
\ No newline at end of file
diff --git a/public/react/src/modules/page/images/float_switch.jpg b/public/react/src/modules/page/images/float_switch.jpg
index 12fc6f8788b42a66affd16e81914f5f2202b23be..3e526259786290dcbdf5b20308b4220341de771e 100644
GIT binary patch
literal 1003
zcmeAS@N?(olHy`uVBq!ia0vp^>Oee^gAGVJ7%YrsU|`<l>Eakt5%+e^{%)C6iR1R?
z-`v}?_};lS)%Iu3$xK(yx}p^LWtU59^AY)o4lbdO>`4<(IdztCC5f^KZWI#SxWRMb
z)PKxL>Jc|?&-6Otb!cW~%D0%C6K)s3-??{oc*U}L?|0AtyXXGg*tBwa#e2>wZrj$_
z*DSgAq<O{zl_!Uf3sf>&-1o?q)zc31zfz*d@ky!R{S&`!jMLNpCZ}IGXL;c>7r)=+
zk{tzmvsQAe@0Q)`Keb)tuE^BO95;1h@7v!wbt>ss`tyoQZ`WP9^7qLu5v?c<9+#31
zua$=cZU{uoVokbbX?##u<nURSO2#LJE!7QA6!@*O%lvn=)_rwY^wnLV|J<$zHs@!v
zi8}?>aa0K|F+R_J=X{j;;jgQfD*Q4%boh7V3xjie1@+>kSyt9J1g?*=S9>@qV9Nd8
z_2<@3_Ko{<X-|!ROL=mGlyT3Q)|$6@E9%`m7B_o;{=_X9*U6dlymx=Ze%lxE;et*j
z1(Ew}LZ_ZjW|p4m{rTZ^rB6X~3S56qKJa(rp}%?;`i1mF4(CqDTT-y}7>8MvW6Pn3
zKC>S`^SQOBI4n2s+*#QJ4W_TITbievCY-H&erL|r2Gi$ri;KgUugxhxcQ%qYqWB(~
z<m}x$Uz?`ScD3fbA1!X5k@sp_-0#QN=jMw<?^*b^;M&{L;=FTN2WEXfx6^VpWA-`g
z=g-!#t+9MRXZB{P4bS$VNWS}jbLWcuClT9|=2`Bq%-H(!88Hq(ah=fD`_nEj`s16B
zP+QhMbMh9A`YCfc?JvrnUHZiM!PXZi%G4C5h`apI^0JsVz4~QYRp^6lHyDoZ*W1Ih
zM^-gveYjq{_Yc<uL$w3-=}%hr)W|-3tnpB4ML<Zn!~Aa6563RLH#^F`dJ{dx*pT6!
z(ZyAJOhu|#pPbyrxV-oFt7S(&=sMnG%**61I`5deFk-K;n4a_B5^3XuX;L4jeeKV^
zGRsE)g3qnnA}9I}J@Y9rZ`8TBao2<sZ5+p4tzIv9ePxb=1?!sg+0z#B=IQ4)JKno{
z&aYI+a_x)A#<a57R72bP9kCit`^u(w<Z1rWd2wxxab+J%-lXl7tMB-InJKmNNBn%{
zewjQW6YW*Hp?ZqHj^y3Gr*%g{L*%LD1K|fxR8m9={xg^si`{3}>y3YFc(7Mu^PZ~6
zi~h4$=3PA4YbX14)pCzl`HNbl8NaPI|IhZFDb{!CDeD8kOw8cv>gTe~DWM4fB7^R+

literal 1303
zcmV+y1?c*TP)<h;3K|Lk000e1NJLTq001Tc003_Y1^@s6fNHV|00001b5ch_0Itp)
z=>Px((Md!>RCodHTRm?aRTQ1ijhEd_9NWlCEX-Q5B}+m13qgWF6bVrfBt!=YS{fv3
z8h!wxM06=qQ6eGHq@qd_rHV-eT`Dhj)-EDuxaVol<nCxDJ1^dScBFTu*?Zr8=e~R9
z%$r@wo(TePb_#@c@VTL9_MHis8<pn^wd&al^nA?|N3Hv{2A+^oU7xxf+7$Rm@G--h
z7MM|1JI%G|0b*<jA+fu=yWK>LVBoYh<u#@*)^&)hV~|45kjtOt@6-{~MQEbOjOj7o
z#)ya4F>9$-jzkd@A8BGNAeiIoVmeRkEU#<ydaMI6LvH8t&No8rCW*0-Ko-Bq16!?Q
zebp1E*VCAMeSN*#@AtnFQr}~OKn-FJKAK?Q8FL;rh-o@zPW!34!C-JcNs?ijrkha|
zU5&!%^P(tLSfIhkaZDoGV~*oM&hS#d+rKH9>tPrU<rv7qeJ*@bPa;@{F`L83a%dk3
zp+T?L`%cdA)5*NJ`J3KjS`iT9Q4$+&4sWEL^rv|$({xH`N~M~Jfqb&Hwe@w9Ccn5K
z1+tn9m4Q+qQ~KeX!w-^9^0VZCabiu1l_b~J*4{|Zr9TQAXQXiEni%4eki<|d%ChWR
zSC>!vl|~hKN$CyA)z#HYa`$~wq8$bx05UubAsL%|*3aIT7|J=fI$|YB`9^-%IipEK
z5QCA-R2)X(rkOp34=TpiBxt<+%&c?5wXZ4$LZ!*w*eeH)0}|71r^x9EmvJ32^yejY
z$z`fn6R|1KX$&;6GjRzif+oh?ned*N?Pc(adBtoMu*Lg5<`uJ5z!vZKm{-hJ0b9J^
zV_q>^1#I!H_SoKEdjXDHw>~z9ZIhS5w<7j33!k*c6SGy&E9MomRlpYS_n24ARsmbQ
z-(y}eTLo<KevjEIhQCywlLP<JO)Ea$zP$Zda;IYcQrgPy74wSODqxHEd(10ltAH)u
z?=i2Ktpc`qzsI~{whGwdUx_`&C&X<}ZXx(rLNR^j<zwtR=`yZU>`Yuz5~D&>q~uY+
zu}hV7FA&pYG(mY1uy~@uF5{|V=uL7#kr)5CB%^y#F_OW{BxRiE`5zkWGOi;Aa)#i+
z(}Uk7{?8>L_A(E8%YY9{f+*wg`1p9dd~tb0Zi2U2;L3v-iJ&K97;|A9$M?J4?q`zg
zm>EYOnpjC@LJSnbqobp7*2^A7arB|eV{V~FVr-%nV=fpSj2>NBzHlIq&|i}zG3ERs
z0uY;JxJ!f4Xml?-pFN0^_&pge{IXUR(<BWcNtAx{?`Th6aJnN$CO5<tnZwPp5PK0Z
z-4Nu=SIBrge!9QE|C_u9bh{IG{+0_X9K&1=s5mzzx#2Yl=HU7D0neE8s6kBAF>~5a
z)vc_oye99uy%h)XFigTLvVXr6@art#V)Q!Cg_=CD)jHN!J#l(1VsJHzjg5`Y($dlw
zLhuLqjZXCDXE6)lxxW~jMP$IAF8)f)^5s^TtjTe?&f($VGua}4ijw<+xlu=^n$u&(
z^dQ{Eh}WJm>UqM(?`-e<suj}>bdk<8o?587aLpKXtkE%Z^kz;}>*5~|bp{|!lhk?6
zxACmQT8QaUt7D7{dGGSBZi?ihtgcU84*ktZG)=lBSli1rF_380^MA+Q<D1H)G6(<w
N002ovPDHLkV1mh)e*^#k

diff --git a/public/react/src/modules/page/images/test/float_switch.jpg b/public/react/src/modules/page/images/test/float_switch.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..12fc6f8788b42a66affd16e81914f5f2202b23be
GIT binary patch
literal 1303
zcmV+y1?c*TP)<h;3K|Lk000e1NJLTq001Tc003_Y1^@s6fNHV|00001b5ch_0Itp)
z=>Px((Md!>RCodHTRm?aRTQ1ijhEd_9NWlCEX-Q5B}+m13qgWF6bVrfBt!=YS{fv3
z8h!wxM06=qQ6eGHq@qd_rHV-eT`Dhj)-EDuxaVol<nCxDJ1^dScBFTu*?Zr8=e~R9
z%$r@wo(TePb_#@c@VTL9_MHis8<pn^wd&al^nA?|N3Hv{2A+^oU7xxf+7$Rm@G--h
z7MM|1JI%G|0b*<jA+fu=yWK>LVBoYh<u#@*)^&)hV~|45kjtOt@6-{~MQEbOjOj7o
z#)ya4F>9$-jzkd@A8BGNAeiIoVmeRkEU#<ydaMI6LvH8t&No8rCW*0-Ko-Bq16!?Q
zebp1E*VCAMeSN*#@AtnFQr}~OKn-FJKAK?Q8FL;rh-o@zPW!34!C-JcNs?ijrkha|
zU5&!%^P(tLSfIhkaZDoGV~*oM&hS#d+rKH9>tPrU<rv7qeJ*@bPa;@{F`L83a%dk3
zp+T?L`%cdA)5*NJ`J3KjS`iT9Q4$+&4sWEL^rv|$({xH`N~M~Jfqb&Hwe@w9Ccn5K
z1+tn9m4Q+qQ~KeX!w-^9^0VZCabiu1l_b~J*4{|Zr9TQAXQXiEni%4eki<|d%ChWR
zSC>!vl|~hKN$CyA)z#HYa`$~wq8$bx05UubAsL%|*3aIT7|J=fI$|YB`9^-%IipEK
z5QCA-R2)X(rkOp34=TpiBxt<+%&c?5wXZ4$LZ!*w*eeH)0}|71r^x9EmvJ32^yejY
z$z`fn6R|1KX$&;6GjRzif+oh?ned*N?Pc(adBtoMu*Lg5<`uJ5z!vZKm{-hJ0b9J^
zV_q>^1#I!H_SoKEdjXDHw>~z9ZIhS5w<7j33!k*c6SGy&E9MomRlpYS_n24ARsmbQ
z-(y}eTLo<KevjEIhQCywlLP<JO)Ea$zP$Zda;IYcQrgPy74wSODqxHEd(10ltAH)u
z?=i2Ktpc`qzsI~{whGwdUx_`&C&X<}ZXx(rLNR^j<zwtR=`yZU>`Yuz5~D&>q~uY+
zu}hV7FA&pYG(mY1uy~@uF5{|V=uL7#kr)5CB%^y#F_OW{BxRiE`5zkWGOi;Aa)#i+
z(}Uk7{?8>L_A(E8%YY9{f+*wg`1p9dd~tb0Zi2U2;L3v-iJ&K97;|A9$M?J4?q`zg
zm>EYOnpjC@LJSnbqobp7*2^A7arB|eV{V~FVr-%nV=fpSj2>NBzHlIq&|i}zG3ERs
z0uY;JxJ!f4Xml?-pFN0^_&pge{IXUR(<BWcNtAx{?`Th6aJnN$CO5<tnZwPp5PK0Z
z-4Nu=SIBrge!9QE|C_u9bh{IG{+0_X9K&1=s5mzzx#2Yl=HU7D0neE8s6kBAF>~5a
z)vc_oye99uy%h)XFigTLvVXr6@art#V)Q!Cg_=CD)jHN!J#l(1VsJHzjg5`Y($dlw
zLhuLqjZXCDXE6)lxxW~jMP$IAF8)f)^5s^TtjTe?&f($VGua}4ijw<+xlu=^n$u&(
z^dQ{Eh}WJm>UqM(?`-e<suj}>bdk<8o?587aLpKXtkE%Z^kz;}>*5~|bp{|!lhk?6
zxACmQT8QaUt7D7{dGGSBZi?ihtgcU84*ktZG)=lBSli1rF_380^MA+Q<D1H)G6(<w
N002ovPDHLkV1mh)e*^#k

literal 0
HcmV?d00001

diff --git a/public/react/src/modules/tpm/jupyter/index.scss b/public/react/src/modules/tpm/jupyter/index.scss
index b860fde03..932b0c89f 100644
--- a/public/react/src/modules/tpm/jupyter/index.scss
+++ b/public/react/src/modules/tpm/jupyter/index.scss
@@ -114,7 +114,7 @@
 
   .ant-drawer-content-wrapper{
     width:330px  !important;
-    box-shadow: -2px 0 8px #070F1A  !important;
+    //box-shadow: -2px 0 8px #070F1A  !important;
   }
   .ant-drawer-body{
     padding: 0px;

From 17ba228586ba39565e1061ef8a2cbd1245991e32 Mon Sep 17 00:00:00 2001
From: daiao <358551898@qq.com>
Date: Tue, 24 Dec 2019 16:14:30 +0800
Subject: [PATCH 08/25] fixbug

---
 app/controllers/subjects_controller.rb | 2 +-
 app/models/hack.rb                     | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/app/controllers/subjects_controller.rb b/app/controllers/subjects_controller.rb
index c8f2f5f57..0009ab2a6 100644
--- a/app/controllers/subjects_controller.rb
+++ b/app/controllers/subjects_controller.rb
@@ -216,10 +216,10 @@ class SubjectsController < ApplicationController
       @shixun.update_column(:repo_name, repo_path.split(".")[0])
       mirror_id =
           if @shixun.is_jupyter?
-            MirrorRepository.where("type_name like '%Jupyter%'").first&.id
             folder = EduSetting.get('shixun_folder')
             path = "#{folder}/#{identifier}"
             FileUtils.mkdir_p(path, :mode => 0777) unless File.directory?(path)
+            MirrorRepository.where("type_name like '%Jupyter%'").first&.id
           else
             MirrorRepository.find_by(type_name: 'Python3.6')&.id
           end
diff --git a/app/models/hack.rb b/app/models/hack.rb
index 35abb8787..d1ec3932c 100644
--- a/app/models/hack.rb
+++ b/app/models/hack.rb
@@ -56,7 +56,7 @@ class Hack < ApplicationRecord
   private
   def send_delete_tiding
     base_attrs = {
-        user_id: user_id, viewed: 0, tiding_type: 'Delete', trigger_user_id: current_user.id
+        user_id: user_id, viewed: 0, tiding_type: 'Delete', trigger_user_id: current_user.id, content: "你删除了题目:#{name}"
     }
     tidings.create!(base_attrs)
   end

From 41c500cc303ed6a52671716860150829df49ecb0 Mon Sep 17 00:00:00 2001
From: daiao <358551898@qq.com>
Date: Tue, 24 Dec 2019 16:20:29 +0800
Subject: [PATCH 09/25] =?UTF-8?q?=E7=94=A8=E6=88=B7=E6=98=AF=E5=90=A6?=
 =?UTF-8?q?=E7=82=B9=E8=B5=9E?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 app/views/hack_user_lastest_codes/show.json.jbuilder | 1 +
 1 file changed, 1 insertion(+)

diff --git a/app/views/hack_user_lastest_codes/show.json.jbuilder b/app/views/hack_user_lastest_codes/show.json.jbuilder
index f3ae49539..098c24546 100644
--- a/app/views/hack_user_lastest_codes/show.json.jbuilder
+++ b/app/views/hack_user_lastest_codes/show.json.jbuilder
@@ -7,6 +7,7 @@ json.hack do
   json.submit_count @hack.submit_num
   json.modify_code @modify
   json.comments_count @hack.discusses.count
+  json.user_praise @hack.praise_treads.select{|pt| pt.user_id == current_user.id}.length > 0
 end
 
 json.test_case do

From c38d9f290f36a072573e9e7ad92c348b769b7097 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=98=8E?= <775174143@qq.com>
Date: Tue, 24 Dec 2019 16:42:56 +0800
Subject: [PATCH 10/25] =?UTF-8?q?=E8=B0=83=E6=95=B4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 public/react/public/css/css_min_all.css           |  4 ++--
 public/react/public/css/edu-all.css               |  6 ++++++
 .../shixunHomework/Listofworksstudentone.js       | 15 +++++++++------
 public/stylesheets/educoder/edu-all.css           |  5 +++++
 public/stylesheets/educoder/edu-main.css          |  4 ++++
 5 files changed, 26 insertions(+), 8 deletions(-)

diff --git a/public/react/public/css/css_min_all.css b/public/react/public/css/css_min_all.css
index cf453ac21..431a4da8e 100755
--- a/public/react/public/css/css_min_all.css
+++ b/public/react/public/css/css_min_all.css
@@ -1883,9 +1883,8 @@ a:hover.task_icons_close{background: url(../images/popup/sy_icons_close.png) -40
 .newupload_nav li:last-child{ border-right: none;}
 .newupload_nav li a{font-size:12px; color:#444;}
 .newupload_nav_hover{ background: #3498db; }
-.newupload_nav_nomal { }
 .newupload_nav_hover a{color: #fff !important; }
-
+.markdown-body { text-align: justify;word-break: break-all;}
 .bor-reds{
     border:1px solid #FF0000!important;
     border-radius: 4px;
@@ -1894,6 +1893,7 @@ a:hover.task_icons_close{background: url(../images/popup/sy_icons_close.png) -40
     border-bottom-right-radius: 4px;
     border-bottom-left-radius: 4px;
 }
+
 @charset "UTF-8";
 
 /*!
diff --git a/public/react/public/css/edu-all.css b/public/react/public/css/edu-all.css
index 5988709eb..141f5b8e1 100644
--- a/public/react/public/css/edu-all.css
+++ b/public/react/public/css/edu-all.css
@@ -3478,3 +3478,9 @@ a.singlepublishtwo{
     /*width: auto !important;*/
     /*max-width: 600px !important;*/
 /*}*/
+
+
+.markdown-body {
+    text-align: justify;
+    word-break: break-all;
+}
\ No newline at end of file
diff --git a/public/react/src/modules/courses/shixunHomework/Listofworksstudentone.js b/public/react/src/modules/courses/shixunHomework/Listofworksstudentone.js
index 459421dcd..1111dcb12 100644
--- a/public/react/src/modules/courses/shixunHomework/Listofworksstudentone.js
+++ b/public/react/src/modules/courses/shixunHomework/Listofworksstudentone.js
@@ -1667,7 +1667,7 @@ class Listofworksstudentone extends Component {
 			],
 			yslpros: false,
 			datajs: [],
-			homework_status: [],
+			homework_status: undefined,
 
 		}
 	}
@@ -3597,7 +3597,14 @@ class Listofworksstudentone extends Component {
 						starttimesend={this.state.starttimesend}
 						typs={this.state.typs}
 					/> : ""}
-					{
+					{homework_status===undefined?
+						<div className={"educontent "}>
+							<div className="edu-back-white">
+								<div className="edu-tab-con-box clearfix edu-txt-center" style={{ width:"100%",height:"200px" }}>
+									<Spin  style={{ width:"100%","line-height":"200px" }}></Spin>
+								</div>
+							</div>
+						</div>:
 						homework_status && homework_status.length === 0 ?
 							<div className="edu-back-white">
 								<NoneData></NoneData>
@@ -3609,11 +3616,7 @@ class Listofworksstudentone extends Component {
 								</div>
 								:
 								<div className={"educontent "}>
-
-
 									<div className="edu-back-white">
-
-
 										<style>
 											{`
 							.startbox{
diff --git a/public/stylesheets/educoder/edu-all.css b/public/stylesheets/educoder/edu-all.css
index 5eca4c649..2832f226f 100644
--- a/public/stylesheets/educoder/edu-all.css
+++ b/public/stylesheets/educoder/edu-all.css
@@ -3798,4 +3798,9 @@ a.singlepublishtwo{
 
 .ant-drawer{
     z-index: 10000 !important;
+}
+
+.markdown-body {
+    text-align: justify;
+    word-break: break-all;
 }
\ No newline at end of file
diff --git a/public/stylesheets/educoder/edu-main.css b/public/stylesheets/educoder/edu-main.css
index 84bca6a78..9de4bfb1d 100644
--- a/public/stylesheets/educoder/edu-main.css
+++ b/public/stylesheets/educoder/edu-main.css
@@ -821,3 +821,7 @@ html>body #ajax-indicator { position: fixed; }
 .footer_con-p{
     color: #898989 !important;
 }
+.markdown-body {
+    text-align: justify;
+    word-break: break-all;
+}
\ No newline at end of file

From cd569750941df3d18a9a3493d15540a1f61226cd Mon Sep 17 00:00:00 2001
From: tangjiang <465264938@qq.com>
Date: Tue, 24 Dec 2019 17:28:50 +0800
Subject: [PATCH 11/25] add comment

---
 public/react/src/AppConfig.js                 |   2 +-
 .../common/components/comment/CommentForm.js  |  50 +++--
 .../common/components/comment/CommentIcon.js  |  12 +-
 .../common/components/comment/CommentItem.js  | 188 +++++++++++-------
 .../common/components/comment/CommentList.js  |  33 ++-
 .../src/common/components/comment/index.js    |  32 ++-
 .../src/common/components/comment/index.scss  |  69 ++++++-
 .../src/common/components/comment/util.js     |  78 ++++++++
 .../src/common/quillForEditor/ImageBlot.js    |   8 +-
 .../developer/components/textNumber/index.js  |  29 ++-
 .../modules/developer/newOrEditTask/index.js  |   2 +-
 .../developer/newOrEditTask/leftpane/index.js |   1 -
 .../studentStudy/leftpane/comment/index.js    | 103 +++++++++-
 .../developer/studentStudy/leftpane/index.js  |  78 ++++++--
 .../studentStudy/leftpane/index.scss          |  24 ++-
 public/react/src/redux/actions/actionTypes.js |   8 +
 public/react/src/redux/actions/comment.js     | 114 +++++++++++
 public/react/src/redux/actions/index.js       |  18 +-
 public/react/src/redux/actions/ojForUser.js   |   4 +-
 public/react/src/redux/actions/ojForm.js      |  78 +++++---
 .../src/redux/reducers/commentReducer.js      |  42 ++++
 public/react/src/redux/reducers/index.js      |   4 +-
 .../src/redux/reducers/ojForUserReducer.js    |  26 ++-
 .../react/src/redux/reducers/ojFormReducer.js |  14 +-
 public/react/src/services/commentService.js   |  45 +++++
 25 files changed, 877 insertions(+), 185 deletions(-)
 create mode 100644 public/react/src/common/components/comment/util.js
 create mode 100644 public/react/src/redux/actions/comment.js
 create mode 100644 public/react/src/redux/reducers/commentReducer.js
 create mode 100644 public/react/src/services/commentService.js

diff --git a/public/react/src/AppConfig.js b/public/react/src/AppConfig.js
index acd18e6c3..158011ea5 100644
--- a/public/react/src/AppConfig.js
+++ b/public/react/src/AppConfig.js
@@ -52,7 +52,7 @@ export function initAxiosInterceptors(props) {
 			//proxy="http://47.96.87.25:48080"
 			proxy="https://pre-newweb.educoder.net"
       proxy="https://test-newweb.educoder.net"
-      proxy="https://test-jupyterweb.educoder.net"
+    //   proxy="https://test-jupyterweb.educoder.net"
 	     //proxy="http://192.168.2.63:3001"
 
     // 在这里使用requestMap控制,避免用户通过双击等操作发出重复的请求;
diff --git a/public/react/src/common/components/comment/CommentForm.js b/public/react/src/common/components/comment/CommentForm.js
index 73e36cff9..7683e2dea 100644
--- a/public/react/src/common/components/comment/CommentForm.js
+++ b/public/react/src/common/components/comment/CommentForm.js
@@ -3,22 +3,24 @@
  * @Author: tangjiang
  * @Github: 
  * @Date: 2019-12-17 17:32:55
- * @LastEditors: tangjiang
- * @LastEditTime: 2019-12-18 17:51:44
+ * @LastEditors  : tangjiang
+ * @LastEditTime : 2019-12-24 17:27:41
  */
+import './index.scss';
 import React, { useState } from 'react';
 import { Form, Button, Input } from 'antd';
 import QuillForEditor from '../../quillForEditor';
-import { QuillDeltaToHtmlConverter } from 'quill-delta-to-html'
+// import { QuillDeltaToHtmlConverter } from 'quill-delta-to-html'
+import {formatDelta} from './util';
 const FormItem = Form.Item;
 
 function CommentForm (props) {
 
   const {
-    commentCtxChagne,
     onCancel,
     onSubmit, 
-    form
+    form,
+    type
   } = props;
 
   const { getFieldDecorator } = form;
@@ -34,22 +36,25 @@ function CommentForm (props) {
   // const { form: { getFieldDecorator } } = props;
   const [showQuill, setShowQuill] = useState(false);
   // 点击输入框
-  const handleInputClick = () => {
+  const handleInputClick = (type) => {
     setShowQuill(true);
   }
   // 取消
   const handleCancle = () => {
     setShowQuill(false);
-    onCancel && onCancel();
+    setCtx('');
+    props.form.resetFields();
+    onCancel && onCancel(); 
   }
 
   // 编辑器内容变化时
   const handleContentChange = (content) => {
+    console.log('编辑器内容', content);
     setCtx(content);
     try {
-      const _html = new QuillDeltaToHtmlConverter(content.ops, {}).convert();
+      // const _html = new QuillDeltaToHtmlConverter(content.ops, {}).convert();
       // props.form.setFieldsValue({'comment': _html.replace(/<\/?[^>]*>/g, '')});
-      props.form.setFieldsValue({'comment': _html});
+      props.form.setFieldsValue({'comment': content});
     } catch (error) {
       console.log(error);
     }
@@ -63,13 +68,25 @@ function CommentForm (props) {
         const content = ctx;
         props.form.setFieldsValue({'comment': ''});
         setCtx('');
-        console.log(content);
-        onSubmit && onSubmit(content);
+        const _html = formatDelta(content.ops);
+        onSubmit && onSubmit(_html);
       }
     });
   }
+
+  const handleShowImage = (url) => {
+    alert(url);
+  }
+
+  // const _clazz = type === 'bottom' ? 'comment_form_bottom_area' : 'comment_form_area';
+  let _clazz;
+  if (type === 'bottom') {
+    _clazz = showQuill ? 'comment_form_bottom_area active' : 'comment_form_bottom_area';
+  } else {
+    _clazz = 'comment_form_area';
+  }
   return (
-    <Form>
+    <Form className={_clazz}>
       <FormItem>
         {
           getFieldDecorator('comment', {
@@ -78,13 +95,13 @@ function CommentForm (props) {
             ],
           })(
             <Input 
-              onClick={handleInputClick}
+              onClick={() => handleInputClick(type)}
               placeholder="说点儿什么~"
+              className={showQuill ? '' : 'show_input'}
               style={{
                 height: showQuill ? '0px' : '40px',
                 overflow: showQuill ? 'hidden' : 'auto',
                 opacity: showQuill ? 0 : 1,
-                transition: 'all .3s' 
               }}
             />
           )
@@ -98,14 +115,15 @@ function CommentForm (props) {
             overflow: showQuill ? 'none' : 'hidden',
             transition: 'all 0.3s'
           }}
-          style={{ height: '150px', overflowY: 'auto' }}
+          style={{ height: '150px' }}
           placeholder="说点儿什么~"
           options={options}
           value={ctx}
+          showUploadImage={handleShowImage}
           onContentChange={handleContentChange}
         />
       </FormItem>
-      <FormItem style={{ textAlign: 'right' }}>
+      <FormItem style={{ textAlign: 'right', display: showQuill ? 'block' : 'none' }}>
         <Button onClick={handleCancle}>取消</Button>
         <Button onClick={handleSubmit} type="primary" style={{ marginLeft: '10px'}}>发送</Button>
       </FormItem>
diff --git a/public/react/src/common/components/comment/CommentIcon.js b/public/react/src/common/components/comment/CommentIcon.js
index 5440e2579..ff3b109e1 100644
--- a/public/react/src/common/components/comment/CommentIcon.js
+++ b/public/react/src/common/components/comment/CommentIcon.js
@@ -3,16 +3,19 @@
  * @Author: tangjiang
  * @Github: 
  * @Date: 2019-12-18 10:49:46
- * @LastEditors: tangjiang
- * @LastEditTime: 2019-12-18 11:39:23
+ * @LastEditors  : tangjiang
+ * @LastEditTime : 2019-12-24 17:05:14
  */
 import './index.scss';
 import React from 'react';
 import { Icon } from 'antd';
+// import MyIcon from '../MyIcon';
 function CommentIcon ({
   type, // 图标类型
   count, // 评论数
   iconClick,
+  iconColor,
+  theme,
   ...props
 }) {
 
@@ -21,10 +24,11 @@ function CommentIcon ({
     iconClick && iconClick();
   }
 
+  const _className = [undefined, null, ''].includes(count) ? 'comment_count_none' : 'comment_count';
   return (
     <span className={`comment_icon_count ${props.className}`} onClick={ handleSpanClick }>
-      <Icon className="comment_icon" type={type} />
-      <span className="comment_count">{ count }</span>
+      <Icon className="comment_icon" type={type} style={{ color: iconColor }} theme={theme}/>
+      <span className={_className}>{ count }</span>
     </span>
   )
 }
diff --git a/public/react/src/common/components/comment/CommentItem.js b/public/react/src/common/components/comment/CommentItem.js
index 19da645f5..28341a47c 100644
--- a/public/react/src/common/components/comment/CommentItem.js
+++ b/public/react/src/common/components/comment/CommentItem.js
@@ -3,104 +3,133 @@
  * @Author: tangjiang
  * @Github: 
  * @Date: 2019-12-17 17:35:17
- * @LastEditors: tangjiang
- * @LastEditTime: 2019-12-19 18:02:28
+ * @LastEditors  : tangjiang
+ * @LastEditTime : 2019-12-24 17:11:59
  */
 import './index.scss';
 import React, { useState } from 'react';
 import CommentIcon from './CommentIcon';
 import { getImageUrl, CNotificationHOC } from 'educoder'
 import { Icon } from 'antd';
-import moment from 'moment';
-// import QuillForEditor from '../../quillForEditor';
 import CommentForm from './CommentForm';
 
-// import {ModalConfirm} from '../ModalConfirm';
 function CommentItem ({
   options,
-  confirm
+  confirm,
+  comment,
+  submitDeleteComment,
+  submitChildComment,
+  likeComment,
+  showOrHideComment
 }) {
   // 显示评论输入框
   const [showQuill, setShowQuill] = useState(false);
   // 加载更多评论内容
-  const [showMore, setShowMore] = useState(false);
+  // const [showMore, setShowMore] = useState(false);
+  // 显示子列数
+  const [showItemCount, setShowItemCount] = useState(1);
   // 箭头方向
   const [arrow, setArrow] = useState(false);
-  // 删除评论
-  const deleteComment = () => {
-    console.log('删除评论...');
+
+  const { 
+    author = {}, // 作者
+    id, // 评论id
+    content, // 回复内容
+    time, // 回复时间
+    hidden, // 是否隐藏
+    // hack_id, // OJ的ID
+    praise_count, // 点赞数
+    user_praise, // 当前用户是否点赞
+    can_delete,
+    children = [] // 子回复
+  } = comment;
+
+  // 删除评论 type: parent | child,  id
+  const deleteComment = (id) => {
     confirm({
       title: '提示',
-      content: (<p>确定要删除该条回复吗?</p>),
+      content: ('确定要删除该条回复吗?'),
       onOk () {
-        console.log('点击了删除');
+        console.log('点击了删除', id);
+        submitDeleteComment && submitDeleteComment(id);
       }
     });
-    // ModalConfirm('提示', (<p>确定要删除该条回复吗?</p>), () => {
-    //   console.log('点击了删除');
-    // });
   }
 
   // 评论头像
-  const commentAvatar = (url) => ( 
-    <img className="item-flex flex-image" src='https://b-ssl.duitang.com/uploads/item/201511/13/20151113110434_kyReJ.jpeg' alt=""/>
+  const commentAvatar = (author) => ( 
+    <img 
+      className="item-flex flex-image" 
+      src={author.image_url ? getImageUrl(`/images/${author.image_url}`) : 'https://b-ssl.duitang.com/uploads/item/201511/13/20151113110434_kyReJ.jpeg'}
+      alt=""
+    />
   );
   
   // 评论信息
-  const commentInfo = () => (
-    <p className="item-header">
-      <span className="item-name">用户名</span>
-      <span className="item-time">{moment(new Date(), 'YYYYMMDD HHmmss').fromNow()}</span>
-      <span className="item-close"><Icon type="close" onClick={deleteComment}/></span>
-    </p>
-  );
+  const commentInfo = (id, author, time, can_delete) => {
+    const _classNames = can_delete ? 'item-close' : 'item-close hide';
+    return (
+      <div className="item-header">
+        <span className="item-name">{author.name || ''}</span>
+        <span className="item-time">{time || ''}</span>
+        <span className={_classNames}>
+          <Icon type="close" onClick={() => deleteComment(id)}/>
+        </span>
+      </div>
+    );  
+  };
 
   // 评论内容
   const commentCtx = (ctx) => (
-    <p className="item-ctx">
-      这是评论内容这是评论内容这是评论内容这是评论内容这是评论内容这是评论内容这是评论内容这是评论内容这是评论内容这是评论内容
-    </p>
+    <p className="item-ctx" dangerouslySetInnerHTML={{ __html: ctx}}></p>
   );
 
   // 加载更多
-  const handleOnLoadMore = () => {
-    if (!arrow) {
-      // 展开所有
-    } else {
-      // 收起
-    }
+  const handleOnLoadMore = (len) => {
+    setShowItemCount(!arrow ? len : 1);
     setArrow(!arrow);
   };
 
   // 评论追加内容
-  const commentAppend = () => {
+  const commentAppend = (children = []) => {
+
+    const len = children.length;
+    const _moreClass = len > 1 ? 'comment_item_loadmore show' : 'comment_item_loadmore'
+    const lastTxt = len - showItemCount;
+    const renderChild = (children) => {
+      return children.map((child, i) => {
+        const {
+          id, // 评论id
+          author = {},
+          time,
+          content,
+          can_delete
+        } = child;
+        const showOrHide = i < showItemCount ? 'comment_item_show' : 'comment_item_hide';
+        return (
+          <li
+            key={`child_${i}`}
+            className={showOrHide}
+          >
+            <div className="comment_item_area">
+              {commentAvatar(author)}
+              <div className="item-flex item-desc">
+                {commentInfo(id, author, time, can_delete)}
+                {commentCtx(content)}
+              </div>
+            </div>
+          </li>
+        );
+      })
+    }
 
+    const _clazz = len > 0 ? 'comment_item_append_list active' : 'comment_item_append_list';
     return (
-      <ul className="comment_item_append_list">
-        <li className="comment_item_area">
-          {commentAvatar()}
-          <div className="item-flex item-desc">
-            {commentInfo()}
-            {commentCtx()}
-          </div>
-        </li>
-        <li className="comment_item_area">
-          {commentAvatar()}
-          <div className="item-flex item-desc">
-            {commentInfo()}
-            {commentCtx()}
-          </div>
-        </li>
-        <li className="comment_item_area">
-          {commentAvatar()}
-          <div className="item-flex item-desc">
-            {commentInfo()}
-            {commentCtx()}
-          </div>
-        </li>
+      <ul className={_clazz}>
+        {renderChild(children)}
 
-        <li className="comment_item_loadmore" onClick={handleOnLoadMore}>
-          <p className="loadmore-txt">展开其余23条评论</p>
+        <li className={_moreClass} onClick={() => handleOnLoadMore(len)}>
+          <p className="loadmore-txt">展开其余{lastTxt}条评论</p>
           <p className="loadmore-icon">
             <Icon type={!arrow ? 'down' : 'up'}/>
           </p>
@@ -109,7 +138,14 @@ function CommentItem ({
     );
   };
   // 点击图标
-  const handleIconClick = () => {}
+  const handleShowOrHide = (id, hidden) => {
+    showOrHideComment && showOrHideComment(id, hidden);
+  }
+
+  // 点赞
+  const handleClickLick = (id) => {
+    likeComment && likeComment(id);
+  }
   
   // 点击评论icon
   const handleClickMessage = () => {
@@ -122,23 +158,28 @@ function CommentItem ({
   }
 
   // 点击保存
-  const handleClickSubmit = (content) => {
-    // 保存并关闭
-    setShowQuill(false);
-    console.log('获取保存内容', content);
+  const handleClickSubmit = (id) => {
+    return (ctx) => {
+      setShowQuill(false);
+      submitChildComment && submitChildComment(id, ctx);
+    }
   }
 
   return (
     <li className="comment_item_area">
-      {commentAvatar()}
+      {commentAvatar(author)}
       <div className="item-flex item-desc">
-        {commentInfo()}
-        {commentCtx()}
+        {commentInfo(id, author, time, can_delete)}
+        {commentCtx(content)}
         
-        {commentAppend()}
+        {commentAppend(children)}
 
         <div className="comment_icon_area">
-          <CommentIcon className='comment-icon-margin' type="eye" count="100" iconClick={handleIconClick}/>
+          <CommentIcon 
+            className='comment-icon-margin' 
+            type={!hidden ? "eye" : 'eye-invisible'} 
+            iconClick={() => handleShowOrHide(id, !hidden ? 1 : 0)}
+          />
           {/* 回复 */}
           <CommentIcon 
             className='comment-icon-margin' 
@@ -146,7 +187,14 @@ function CommentItem ({
             iconClick={handleClickMessage}
           />
           {/* 点赞 */}
-          <CommentIcon/>
+          <CommentIcon 
+            iconColor={ user_praise ? '#5091FF' : '' }
+            className='comment-icon-margin'
+            theme={user_praise ? 'filled' : ''}
+            type="like"
+            count={praise_count}
+            iconClick={() => handleClickLick(id)}
+          />
         </div>
 
         <div
@@ -154,7 +202,7 @@ function CommentItem ({
           className="comment_item_quill">
           <CommentForm 
             onCancel={handleClickCancel}
-            onSubmit={handleClickSubmit}
+            onSubmit={handleClickSubmit(id)}
           />
         </div>
       </div>
diff --git a/public/react/src/common/components/comment/CommentList.js b/public/react/src/common/components/comment/CommentList.js
index 9d8cde87b..dc93bcc10 100644
--- a/public/react/src/common/components/comment/CommentList.js
+++ b/public/react/src/common/components/comment/CommentList.js
@@ -3,16 +3,41 @@
  * @Author: tangjiang
  * @Github: 
  * @Date: 2019-12-17 17:34:00
- * @LastEditors: tangjiang
- * @LastEditTime: 2019-12-18 11:48:09
+ * @LastEditors  : tangjiang
+ * @LastEditTime : 2019-12-24 11:30:14
  */
 import './index.scss';
 import React from 'react';
 import CommentItem from './CommentItem';
-function CommentList ({}) {
+function CommentList (props) {
+  const {
+    commentLists, // 评论列表
+    submitChildComment,
+    submitDeleteComment,
+    likeComment,
+    showOrHideComment
+  } = props;
+
+  const {comments = []} = commentLists;
+
+  const renderLi = () => {
+    return comments.map((item, index) => {
+      return (
+        <CommentItem 
+          key={`item_${index}`}
+          submitChildComment={submitChildComment}
+          submitDeleteComment={submitDeleteComment}
+          comment={item} 
+          likeComment={likeComment}
+          showOrHideComment={showOrHideComment}
+        />
+      );
+    });
+  }
+
   return (
     <ul className="comment_list_wrapper">
-      <CommentItem />
+      {renderLi()}
     </ul>
   );
 }
diff --git a/public/react/src/common/components/comment/index.js b/public/react/src/common/components/comment/index.js
index f0ecf3309..15e86c980 100644
--- a/public/react/src/common/components/comment/index.js
+++ b/public/react/src/common/components/comment/index.js
@@ -3,18 +3,40 @@
  * @Author: tangjiang
  * @Github: 
  * @Date: 2019-12-17 17:31:33
- * @LastEditors: tangjiang
- * @LastEditTime: 2019-12-18 11:47:39
+ * @LastEditors  : tangjiang
+ * @LastEditTime : 2019-12-24 15:47:07
  */
 import React from 'react';
-import CommentForm from './CommentForm';
+// import CommentForm from './CommentForm';
 import CommentList from './CommentList';
 function Comment (props) {
 
+  const { 
+    commentLists,
+    // addComment,
+    // cancelComment,
+    addChildComment,
+    likeComment,
+    showOrHideComment,
+    submitDeleteComment
+  } = props;
+  
+  // const handleCancelComment = () => {
+  //   cancelComment && cancelComment();
+  // };
   return (
     <React.Fragment>
-      <CommentForm />
-      <CommentList />
+      {/* <CommentForm 
+        onCancel={handleCancelComment}
+        onSubmit={addComment}
+      /> */}
+      <CommentList 
+        likeComment={likeComment}
+        showOrHideComment={showOrHideComment}
+        commentLists={commentLists}
+        submitChildComment={addChildComment}
+        submitDeleteComment={submitDeleteComment}
+      />
     </React.Fragment>
   );
 }
diff --git a/public/react/src/common/components/comment/index.scss b/public/react/src/common/components/comment/index.scss
index 816e6da6c..264a5e2aa 100644
--- a/public/react/src/common/components/comment/index.scss
+++ b/public/react/src/common/components/comment/index.scss
@@ -8,8 +8,14 @@ $ml: 20px;
 
 .comment_list_wrapper{
   box-sizing: border-box;
-  border-top: 1px solid $bdColor;
+  // border-top: 1px solid $bdColor;
 
+  .comment_item_show{
+    display: block;
+  }
+  .comment_item_hide{
+    display: none;
+  }
   .comment_item_area{
     display: flex;
     padding: 20px 0;
@@ -34,8 +40,13 @@ $ml: 20px;
         margin-left: $ml;
       }
       .item-close{
-        float: right;
+        display: inline-block;
         cursor: pointer;
+        float: right;
+      }
+
+      .item-close.hide{
+        display: none;
       }
     }
     .item-ctx{
@@ -50,13 +61,16 @@ $ml: 20px;
       margin-top: 10px;
 
       .comment-icon-margin{
-        margin-left: 30px;
+        margin-left: 20px;
+      }
+      .comment-icon-margin-10{
+        margin-left: 10px;
       }
     }
 
-    .comment_item_quill{
-      margin-top: 20px;
-    }
+    // .comment_item_quill{
+    //   // margin-top: 10px;
+    // }
   }
   .comment_icon_count{
     cursor: pointer;
@@ -71,6 +85,9 @@ $ml: 20px;
       margin-left: 10px;
       transition: color .3s;
     }
+    .comment_count_none{
+      margin-left: 0;
+    }
 
     &:hover{
       .comment_icon,
@@ -80,11 +97,15 @@ $ml: 20px;
     }
   }
   .comment_item_append_list{
+    display: none;
     position: relative;
     background-color: $bgColor;
     border-radius: 5px;
     padding: 0 15px 10px;
     margin: 15px 0;
+    &.active{
+      display: block;
+    }
     &::before {
       position: absolute;
       left: 15px;
@@ -98,6 +119,7 @@ $ml: 20px;
     }
 
     .comment_item_loadmore{
+      display: none;
       padding-top: 10px;
       cursor: pointer;
       .loadmore-txt,
@@ -106,6 +128,41 @@ $ml: 20px;
         text-align: center;
         font-size: $fz12;
       }
+
+      &.show{
+        display: block;
+      }
     }
   }
+}
+
+.comment_form_area,
+.comment_form_bottom_area{
+  width: 100%;
+}
+.comment_form_area{
+  position: relative;
+  background: #fff;
+  // top: 10px;
+  .ant-form-explain{
+    padding-left: 0px;
+  }
+  .show_input{
+    margin-top: 10px;
+  }
+}
+
+.comment_form_bottom_area{
+  position: relative;
+  background: #fff;
+  top: 10px;
+
+  &.active{
+    position: absolute;
+    background: #fff;
+    left: 0px;
+    right: 0px;
+    top: -220px;
+    padding: 0 20px;
+  }
 }
\ No newline at end of file
diff --git a/public/react/src/common/components/comment/util.js b/public/react/src/common/components/comment/util.js
new file mode 100644
index 000000000..5aac8c64e
--- /dev/null
+++ b/public/react/src/common/components/comment/util.js
@@ -0,0 +1,78 @@
+/*
+ * @Description: quill delta -> html
+ * @Author: tangjiang
+ * @Github: 
+ * @Date: 2019-12-24 08:51:25
+ * @LastEditors  : tangjiang
+ * @LastEditTime : 2019-12-24 10:45:44
+ */
+export const formatDelta = (deltas) => {
+
+  let formatted = [];
+
+  deltas.forEach(element => {
+    let text = null;
+    // 没有图片时
+    if (!element['insert']['image']) {
+      text = element['insert']; // 获取插入的内容
+      // 元素有属性时
+      if (element['attributes']) {
+        // 获取所有的key值
+        const keys = Object.keys(element['attributes']);
+        keys.forEach(key => {
+          text = operate(text, key, element['attributes'][key]);
+        });
+      }
+    } else {
+      const image = element['insert']['image'];
+      const {url, alt} = image;
+      if (url && (url.startsWith('http') || url.startsWith('https'))) {
+        text = `
+          <img
+            src="${url}"
+            style="{display: 'inline-block'}"
+            width="60px"
+            height="30px"
+            alt="${alt}"
+          />
+        `;
+        // text = "<img src="+url+" width='60px' height='30px' onclick='' alt="+alt+"/>";
+      }
+    }
+
+    formatted.push(text);
+  });
+
+  return formatted.join('');
+}
+
+/**
+ * @param {*} text 文本内容
+ * @param {*} key 属性key
+ * @param {*} value 属性key对应的值
+ */
+export const operate = (text, key, value) => {
+  let operatedText = null;
+
+  switch (key) {
+    case 'bold':
+      operatedText = `<strong>${text}</strong>`;
+      break;
+    case 'italic':
+      operatedText = `<i>${text}</i>`;
+      break;
+    case 'strike':
+      operatedText = `<s>${text}</s>`;
+      break;
+    case 'underline':
+      operatedText = `<u>${text}</u>`;
+      break;
+    case 'link':
+      operatedText = `<a href="${value}" target="blank">${text}</a>`;
+      break;
+    default: 
+      operatedText = text;
+  }
+
+  return operatedText;
+}
diff --git a/public/react/src/common/quillForEditor/ImageBlot.js b/public/react/src/common/quillForEditor/ImageBlot.js
index 091bd2c1f..1b474d5dc 100644
--- a/public/react/src/common/quillForEditor/ImageBlot.js
+++ b/public/react/src/common/quillForEditor/ImageBlot.js
@@ -3,8 +3,8 @@
  * @Author: tangjiang
  * @Github: 
  * @Date: 2019-12-16 15:50:45
- * @LastEditors: tangjiang
- * @LastEditTime: 2019-12-17 16:44:48
+ * @LastEditors  : tangjiang
+ * @LastEditTime : 2019-12-24 09:44:03
  */
 import Quill from "quill";
 
@@ -43,8 +43,8 @@ export default class ImageBlot extends BlockEmbed {
       alt: node.getAttribute('alt'),
       url: node.getAttribute('src'),
       onclick: node.onclick,
-      // width: node.width,
-      // height: node.height,
+      width: node.width,
+      height: node.height,
       display: node.getAttribute('display')
     };
   }
diff --git a/public/react/src/modules/developer/components/textNumber/index.js b/public/react/src/modules/developer/components/textNumber/index.js
index 878d49064..77a58c3e8 100644
--- a/public/react/src/modules/developer/components/textNumber/index.js
+++ b/public/react/src/modules/developer/components/textNumber/index.js
@@ -3,8 +3,8 @@
  * @Author: tangjiang
  * @Github: 
  * @Date: 2019-11-27 10:58:37
- * @LastEditors: tangjiang
- * @LastEditTime: 2019-11-27 14:22:38
+ * @LastEditors  : tangjiang
+ * @LastEditTime : 2019-12-24 16:48:56
  */
 import './index.scss';
 import React from 'react';
@@ -19,8 +19,17 @@ const TextNumber = (props) => {
    * type: 内容  文字或图标
    * onIconClick: 点击图标时的回调函数
    */
-  const { text, number, position = 'horizontal', type = 'label', onIconClick} = props;
+  const { 
+    text,
+    number,
+    position = 'horizontal',
+    type = 'label',
+    onIconClick,
+    className,
+    theme = 'outlined'
+  } = props;
 
+  // console.log('style=====>>>>>>', style);
   const handleIconClick = () => {
     onIconClick && onIconClick();
   }
@@ -35,11 +44,17 @@ const TextNumber = (props) => {
     }
     return '';
   }
-  const renderCtx = () => {
+  const renderCtx = (className, theme) => {
     if (type === 'icon') { // 图标加文字时
+      const _className = `text_number_area text_icon_numb flex_${position} ${className}`;
       return (
-        <div className={`text_number_area text_icon_numb flex_${position}`}>
-          <Icon onClick={handleIconClick} type={text} className={'numb_icon'}></Icon>
+        <div className={_className}>
+          <Icon 
+            theme={theme}
+            onClick={handleIconClick}
+            type={text} 
+            className={'numb_icon'}
+          ></Icon>
           {renderNumb()}
         </div>
       )
@@ -54,7 +69,7 @@ const TextNumber = (props) => {
   }
   return (
     <React.Fragment>
-      {renderCtx()}
+      {renderCtx(className, theme)}
     </React.Fragment>
   );
 }
diff --git a/public/react/src/modules/developer/newOrEditTask/index.js b/public/react/src/modules/developer/newOrEditTask/index.js
index b498abe0d..a67da5bb6 100644
--- a/public/react/src/modules/developer/newOrEditTask/index.js
+++ b/public/react/src/modules/developer/newOrEditTask/index.js
@@ -9,7 +9,7 @@ import './index.scss';
 import React, { useEffect } from 'react';
 import { connect } from 'react-redux';
 import SplitPane from 'react-split-pane';// import { Form } from 'antd';
-import { Button, Modal } from 'antd';
+import { Button } from 'antd';
 import LeftPane from './leftpane';
 import RightPane from './rightpane';
 import { withRouter } from 'react-router';
diff --git a/public/react/src/modules/developer/newOrEditTask/leftpane/index.js b/public/react/src/modules/developer/newOrEditTask/leftpane/index.js
index 781b82699..ec0ca1416 100644
--- a/public/react/src/modules/developer/newOrEditTask/leftpane/index.js
+++ b/public/react/src/modules/developer/newOrEditTask/leftpane/index.js
@@ -11,7 +11,6 @@ import React, { useState, useMemo } from 'react';
 // import { Tabs } from 'antd';
 import EditorTab from './editorTab';
 import PrevTab from './prevTab';
-import CommitTab from './commitTab';
 
 // const { TabPane } = Tabs;
 
diff --git a/public/react/src/modules/developer/studentStudy/leftpane/comment/index.js b/public/react/src/modules/developer/studentStudy/leftpane/comment/index.js
index ca7160117..46d7b4e38 100644
--- a/public/react/src/modules/developer/studentStudy/leftpane/comment/index.js
+++ b/public/react/src/modules/developer/studentStudy/leftpane/comment/index.js
@@ -3,19 +3,112 @@
  * @Author: tangjiang
  * @Github: 
  * @Date: 2019-11-27 09:49:35
- * @LastEditors: tangjiang
- * @LastEditTime: 2019-12-17 17:46:05
+ * @LastEditors  : tangjiang
+ * @LastEditTime : 2019-12-24 17:10:14
  */
 import './index.scss';
-import React from 'react';
+import React, { useEffect } from 'react';
 import Comment from '../../../../../common/components/comment';
+import { connect } from 'react-redux';
+import actions from '../../../../../redux/actions';
+
 const CommentTask = (props) => {
 
+  const {
+    identifier,
+    commentLists,
+    addComment,
+    likeComment,
+    deleteComment,
+    getCommentLists,
+    showOrHideComment,
+    replayChildComment
+  } = props;
+
+  useEffect(() => {
+    if (identifier) {
+      // 获取评论列表数据
+      getCommentLists(identifier);
+    }
+  }, [identifier]);
+
+  // 添加评论
+  const handleAddComment = (ctx) => {
+    console.log('添加的评论内容: ', ctx);
+    addComment(identifier, {
+      comments: {
+        content: ctx
+      }
+    });
+  };
+  // 添加子评论
+  const handleAddChildComment = (parentId, ctx) => {
+    replayChildComment(identifier, {
+      comments: {
+        content: ctx,
+        parent_id: parentId
+      }
+    });
+  }
+  // 删除评论
+  const handleSubmitDeleteComment = (id) => {
+    console.log('删除评论:', identifier, id);
+    deleteComment(identifier, id);
+  }
+
+  // 点赞
+  const handleLikeComment = (id) => {
+    likeComment(identifier, id, {
+      container_type: 'Discuss',
+      type: 1
+    });
+  }
+
+  // 显示或隐藏
+  const handleShowOrHideComment = (id, hidden) => {
+    showOrHideComment(identifier, id, {
+      hidden
+    });
+  }
+
   return (
     <div className="task_comment_task">
-      <Comment />
+      <Comment 
+        commentLists={commentLists}
+        addComment={handleAddComment}
+        addChildComment={handleAddChildComment}
+        likeComment={handleLikeComment}
+        showOrHideComment={handleShowOrHideComment}
+        submitDeleteComment={handleSubmitDeleteComment}
+      />
     </div>
   )
 }
 
-export default CommentTask;
+const mapStateToProps = (state) => {
+  const {
+    commentLists // 评论列表
+  } = state.commentReducer;
+  const {
+    comment_identifier
+  } = state.ojForUserReducer;
+  return {
+    commentLists,
+    identifier: comment_identifier
+  }
+}
+
+const mapDispatchToProps = (dispatch) => ({
+  // getCommentLists: (identifier) => dispatch(action.getCommentLists(identifier)) 
+  getCommentLists: (identifier) => dispatch(actions.getCommentLists(identifier)),
+  addComment: (identifier, comments) => dispatch(actions.addComment(identifier, comments)),
+  replayChildComment: (identifier, comment) => dispatch(actions.replayChildComment(identifier, comment)),
+  deleteComment: (identifier, id) => dispatch(actions.deleteComment(identifier, id)),
+  likeComment: (identifier, id, params) => dispatch(actions.likeComment(identifier, id, params)),
+  showOrHideComment: (identifier, id, params) => dispatch(actions.showOrHideComment(identifier, id, params)),
+})
+
+export default connect(
+  mapStateToProps,
+  mapDispatchToProps
+)(CommentTask);
diff --git a/public/react/src/modules/developer/studentStudy/leftpane/index.js b/public/react/src/modules/developer/studentStudy/leftpane/index.js
index 347f4b4f8..53e932db1 100644
--- a/public/react/src/modules/developer/studentStudy/leftpane/index.js
+++ b/public/react/src/modules/developer/studentStudy/leftpane/index.js
@@ -3,8 +3,8 @@
  * @Author: tangjiang
  * @Github: 
  * @Date: 2019-11-23 11:33:41
- * @LastEditors: tangjiang
- * @LastEditTime: 2019-12-19 18:03:22
+ * @LastEditors  : tangjiang
+ * @LastEditTime : 2019-12-24 17:16:54
 //  */
 import './index.scss';
 import React, { useState, useEffect, useMemo } from 'react';
@@ -15,12 +15,19 @@ import CommitRecord from './commitRecord';
 import TaskDescription from './taskDescription';
 import TextNumber from './../../components/textNumber';
 import actions from '../../../../redux/actions';
+import CommentForm from '../../../../common/components/comment/CommentForm';
 // const { TabPane } = Tabs;
 
 const LeftPane = (props) => {
 
   const { hack, userCodeTab } = props;
-  const { pass_count, submit_count } = hack;
+  const { 
+    pass_count,
+    submit_count,
+    praises_count, /* 点赞数 */
+    comments_count, /* 评论数*/
+    user_praise // 用户是否点赞
+  } = hack;
   const [defaultActiveKey, setDefaultActiveKey] = useState('comment');
   
   const navItem = [
@@ -32,10 +39,10 @@ const LeftPane = (props) => {
       title: '提交记录',
       key: 'record'
     },
-    // {
-    //   title: '评论',
-    //   key: 'comment'
-    // }
+    {
+      title: '评论',
+      key: 'comment'
+    }
   ];
 
   const Comp = {
@@ -45,7 +52,6 @@ const LeftPane = (props) => {
   };
 
   useEffect(() => {
-    console.log('====>>>>', userCodeTab);
     setDefaultActiveKey(userCodeTab);
   }, [userCodeTab])
 
@@ -69,18 +75,34 @@ const LeftPane = (props) => {
 
   // 点击消息
   const handleClickMessage = () => {
-    console.log('点击的消息图标---------');
+    // 切换到评论tab
+    setDefaultActiveKey('comment');
   }
 
    // 点击点赞
   const handleClickLike = () => {
-    console.log('点击的Like---------');
-  }
+    // 对OJ进行点赞
+    const {id, identifier } = props.hack;
+    props.likeComment(identifier, id, {
+      container_type: 'Hack',
+      type: 1
+    });
+  };
 
    // 点击不喜欢
-  const handleClickDisLike = () => {
-    console.log('点击的DisLike---------');
-  }
+  // const handleClickDisLike = () => {
+  //   console.log('点击的DisLike---------');
+  // }
+
+  // 添加评论
+  const handleAddComment = (ctx) => {
+    console.log('添加的评论内容: ', ctx, props.identifier);
+    props.identifier && props.addComment(props.identifier, {
+      comments: {
+        content: ctx
+      }
+    });
+  };
 
   return (
     <React.Fragment>
@@ -91,26 +113,46 @@ const LeftPane = (props) => {
         { renderComp }
       </div>
       <div className={'number_area'}>
-        <div className="number_flex flex_count">
+        <div className="number_flex flex_count" style={{ display: defaultActiveKey !== 'comment' ? 'flex' : 'none'}}>
           <TextNumber text="通过次数" number={pass_count} position="vertical"/>
           <Divider type="vertical" style={{ height: '20px', margin: '10px 20px' }}/>
           <TextNumber text="提交次数" number={submit_count} position="vertical"/>
         </div>
+        <div className="number_flex flex_quill" style={{ display: defaultActiveKey === 'comment' ? 'flex' : 'none'}}>
+          <CommentForm 
+            onSubmit={handleAddComment}
+            type="bottom"
+          />
+        </div>
+        <div className="number_flex flex_info">
+          <TextNumber text="message" number={comments_count} type="icon" onIconClick={handleClickMessage}/>
+          <TextNumber 
+            className={user_praise ? 'like active' : 'like'}
+            text="like" 
+            number={praises_count}
+            theme={user_praise ? 'filled' : ''}
+            type="icon" 
+            onIconClick={handleClickLike}/>
+          {/* <TextNumber text="dislike" number={0} type="icon" onIconClick={handleClickDisLike}/> */}
+        </div>
       </div>
     </React.Fragment>
   );
 }
 
 const mapStateToProps = (state) => {
-  const { hack, userCodeTab} = state.ojForUserReducer;
+  const { hack, userCodeTab, comment_identifier} = state.ojForUserReducer;
   return {
     hack,
-    userCodeTab
+    userCodeTab,
+    identifier: comment_identifier
   }
 }
 // changeUserCodeTab
 const mapDispatchToProps = (dispatch) => ({
-  changeUserCodeTab: (key) => dispatch(actions.changeUserCodeTab(key))
+  changeUserCodeTab: (key) => dispatch(actions.changeUserCodeTab(key)),
+  likeComment: (identifier, id, params) => dispatch(actions.likeComment(identifier, id, params)),
+  addComment: (identifier, comments) => dispatch(actions.addComment(identifier, comments))
 });
 export default connect(
   mapStateToProps,
diff --git a/public/react/src/modules/developer/studentStudy/leftpane/index.scss b/public/react/src/modules/developer/studentStudy/leftpane/index.scss
index b5362429f..2468ba368 100644
--- a/public/react/src/modules/developer/studentStudy/leftpane/index.scss
+++ b/public/react/src/modules/developer/studentStudy/leftpane/index.scss
@@ -21,13 +21,33 @@
   background: #fff;
 
   .flex_count,
-  .flex_info{
+  .flex_info,
+  .flex_quill{
     display: flex;
     flex-direction: row;
     justify-content: space-between;
   }
   .flex_info{
-    width: 200px;
+    // width: 140px;
+    justify-content: flex-end;
+
+    .like{
+      margin-left: 20px
+    }
+    .like.active{
+      .numb_icon{
+        color: #5091FF;
+      }
+    }
+  }
+
+  .flex_quill{
+    // position: relative;
+    flex: 1;
+    align-items: center;
+    height: 100%;
+    top: 10px;
+    margin-right: 20px;
   }
 }
 
diff --git a/public/react/src/redux/actions/actionTypes.js b/public/react/src/redux/actions/actionTypes.js
index 474ecb382..deeb8fa93 100644
--- a/public/react/src/redux/actions/actionTypes.js
+++ b/public/react/src/redux/actions/actionTypes.js
@@ -24,6 +24,7 @@ const types = {
   DELETE_TEST_CASE: 'DELETE_TEST_CASE', // 删除测试用例
   SAVE_TEST_CASE: 'SAVE_TEST_CASE', // 保存测试用例
   SAVE_USE_TEST_CASE_VALUE: 'SAVE_USE_TEST_CASE_VALUE', // 用户自定义测试用例值
+  CHANGE_PUBLISH_VALUE: 'CHANGE_PUBLISH_VALUE', // 改变发布状态值
   CLEAR_JSFORM_STORE: 'CLEAR_JSFORM_STORE', // 清空测试用例
   SAVE_EDIT_OJ_FORM_AND_TEST_CASE: 'SAVE_EDIT_OJ_FORM_AND_TEST_CASE', // 保存根据id获取的表单及测试用例值
   TEST_CODE_STATUS: 'TEST_CODE_STATUS', // 代码调试状态
@@ -53,6 +54,7 @@ const types = {
   SAVE_EDITOR_CODE: 'SAVE_EDITOR_CODE', // 保存详情页面中编辑时的代码
   CLICK_OPERATE_TYPE: 'CLICK_OPERATE_TYPE', // 点击类型
   CLEAR_OJ_FOR_USER_REDUCER: 'CLEAR_OJ_FOR_USER_REDUCER', // 退出时清空 ojForUserReducer保存内容
+  ADD_OJ_LIKE_COUNT: 'ADD_OJ_LIKE_COUNT', // 增加点赞数
   /*** jupyter  */
   GET_JUPYTER_DATA_SETS: 'GET_JUPYTER_DATA_SETS', // jupyter 数据集
   GET_JUPYTER_TPI_URL: 'GET_JUPYTER_TPI_URL', // 获取 jupyter url
@@ -67,6 +69,12 @@ const types = {
   CHANGE_JYPYTER_TIME: 'CHANGE_JYPYTER_TIME',//增加15分钟
   CHANGE_EXTENDED_TIME: 'CHANGE_EXTENDED_TIME',//延时
   CHANGE_UPDETA_SPIN: 'CHANGE_UPDETA_SPIN',//加载
+  /*** 评论 */
+  ADD_COMMENTS: 'ADD_COMMENTS', // 添加评论
+  GET_COMMENT_LISTS: 'GET_COMMENT_LISTS', // 获取评论列表
+  REPLAY_CHILD_COMMENTS: 'REPLAY_CHILD_COMMENTS', // 子回复
+  DELETE_COMMENTS: 'DELETE_COMMENTS', // 删除评论
+  SAVE_COMMENT_IDENTIFIER: 'SAVE_COMMENT_IDENTIFIER' // 评论时的identifier
 }
 
 export default types;
diff --git a/public/react/src/redux/actions/comment.js b/public/react/src/redux/actions/comment.js
new file mode 100644
index 000000000..7927e3cd6
--- /dev/null
+++ b/public/react/src/redux/actions/comment.js
@@ -0,0 +1,114 @@
+/*
+ * @Description: 
+ * @Author: tangjiang
+ * @Github: 
+ * @Date: 2019-12-23 10:53:25
+ * @LastEditors  : tangjiang
+ * @LastEditTime : 2019-12-24 16:17:00
+ */
+import types from "./actionTypes";
+
+import {
+  fetchAddComment,
+  fetchCommentLists,
+  fetchAddChildComment,
+  fetchDeleteComment,
+  fetchLikeComment,
+  fetchShowOrHideComment
+} from '../../services/commentService';
+
+// 添加评论
+export const addComment = (identifier, comments) => {
+  return (dispatch) => {
+    fetchAddComment(identifier, comments).then(res => {
+      if (res.status === 200) {
+        // 重新加载评论列表
+        dispatch(getCommentLists(identifier));
+      }
+    });
+  }
+};
+
+// 获取评论列表
+export const getCommentLists = (identifier) => {
+  return (dispatch) => {
+    fetchCommentLists(identifier).then(res => {
+      console.log('获取评论列表: ====>>>>', res);
+      if (res.status === 200) {
+        const {data} = res;
+        dispatch({
+          type: types.GET_COMMENT_LISTS,
+          payload: data
+        })
+      }
+    });
+  }
+}
+
+// 子回复 
+export const replayChildComment = (identifier, comment) => {
+  return (dispatch) => {
+    fetchAddChildComment(identifier, comment).then(res => {
+      // console.log('添加子评论成功: ====>>>>', res);
+      if (res.status === 200) {
+        // 重新加载评论列表
+        dispatch(getCommentLists(identifier));
+      }
+    });
+  }
+}
+
+// 删除评论
+export const deleteComment = (identifier, delId) => {
+  return (dispatch) => {
+    fetchDeleteComment(identifier, delId).then(res => {
+      if (res.status === 200) {
+        // 重新加载评论列表
+        dispatch(getCommentLists(identifier));
+      }
+    });
+  }
+}
+
+// 点赞
+export const likeComment = (identifier, id, params, cb) => {
+  return (dispatch) => {
+    fetchLikeComment(id, params).then(res => {
+      if (res.status === 200) {
+        // 重新加载评论列表
+        const {container_type} = params;
+        // if (container_type === 'Discuss') {
+        //   dispatch(getCommentLists(identifier))
+        // } else if {
+        // }
+        const {praise_count} = res.data;
+        switch (container_type) {
+          case 'Discuss':
+            dispatch(getCommentLists(identifier))
+            break;
+          case 'Hack':
+            dispatch({
+              type: types.ADD_OJ_LIKE_COUNT,
+              payload: praise_count
+            });
+            break;
+          default:
+            break;
+        }
+      }
+    })
+  }
+}
+
+// 显示或隐藏评论
+export const showOrHideComment = (identifier, id, params) => {
+  return (dispatch) => {
+    fetchShowOrHideComment(identifier, id, params).then(res => {
+      if (res.status === 200) {
+        // 重新加载评论列表
+        dispatch(getCommentLists(identifier));
+      }
+    });
+  }
+}
+
diff --git a/public/react/src/redux/actions/index.js b/public/react/src/redux/actions/index.js
index ebea3f5f5..197673f80 100644
--- a/public/react/src/redux/actions/index.js
+++ b/public/react/src/redux/actions/index.js
@@ -65,6 +65,15 @@ import {
   getUserInfoForNew
 } from './user';
 
+import {
+  addComment,
+  getCommentLists,
+  replayChildComment,
+  deleteComment,
+  likeComment,
+  showOrHideComment
+} from './comment';
+
 import {
   getJupyterTpiDataSet,
   getJupyterTpiUrl,
@@ -137,6 +146,13 @@ export default {
   reset_with_tpi,
   addjypertime,
   active_with_tpi,
-  updataspinning
+  updataspinning,
   // isUpdateCodeCtx
+  // 评论
+  addComment,
+  getCommentLists,
+  replayChildComment,
+  deleteComment,
+  likeComment,
+  showOrHideComment,
 }
\ No newline at end of file
diff --git a/public/react/src/redux/actions/ojForUser.js b/public/react/src/redux/actions/ojForUser.js
index 8a44677ef..db2b7c300 100644
--- a/public/react/src/redux/actions/ojForUser.js
+++ b/public/react/src/redux/actions/ojForUser.js
@@ -3,8 +3,8 @@
  * @Author: tangjiang
  * @Github: 
  * @Date: 2019-11-27 13:42:11
- * @LastEditors: tangjiang
- * @LastEditTime: 2019-12-20 19:30:30
+ * @LastEditors  : tangjiang
+ * @LastEditTime : 2019-12-23 11:55:48
  */
 import types from "./actionTypes";
 import { Base64 } from 'js-base64';
diff --git a/public/react/src/redux/actions/ojForm.js b/public/react/src/redux/actions/ojForm.js
index b4d43812d..68185ed7b 100644
--- a/public/react/src/redux/actions/ojForm.js
+++ b/public/react/src/redux/actions/ojForm.js
@@ -3,8 +3,8 @@
  * @Author: tangjiang
  * @Github: 
  * @Date: 2019-11-20 16:35:46
- * @LastEditors: tangjiang
- * @LastEditTime: 2019-12-20 19:54:09
+ * @LastEditors  : tangjiang
+ * @LastEditTime : 2019-12-23 10:55:28
  */
 import types from './actionTypes';
 import CONST from '../../constants';
@@ -86,16 +86,16 @@ const payloadInfo = (key, value, errMsg, validateInfo) => ({
 });
 
 // 接口调用成功后,跳转至列表页
-function linkToDev (dispatch, props) {
-  toStore('oj_description', '');
-  dispatch({
-    type: types.IS_MY_SOURCE,
-    payload: true
-  });
-  setTimeout(() => {
-    props.history.push('/problems');
-  }, 1000);
-}
+// function linkToDev (dispatch, props) {
+//   toStore('oj_description', '');
+//   dispatch({
+//     type: types.IS_MY_SOURCE,
+//     payload: true
+//   });
+//   setTimeout(() => {
+//     props.history.push('/problems');
+//   }, 1000);
+// }
 
 // 表单提交验证
 export const validateOjForm = (props, type) => {
@@ -250,18 +250,24 @@ export const validateOjForm = (props, type) => {
       if (type === 'publish') {
         // 提示发布信息
         publishTask(identifier).then(res => {
+          dispatch({
+            type: types.PUBLISH_LOADING_STATUS,
+            payload: false
+          });
+
           if (res.data.status === 0) {
             // message.success('发布成功!');
             notification.success({
               message: '提示',
               description: '发布成功!'
             });
-            linkToDev(dispatch, props);
+            // linkToDev(dispatch, props);
+            // 改变发布状态值 0 => 1
+            dispatch({
+              type: types.CHANGE_PUBLISH_VALUE,
+              payload: 1
+            });
           }
-          dispatch({
-            type: types.PUBLISH_LOADING_STATUS,
-            payload: false
-          });
         }).catch(() => {
           dispatch({
             type: types.PUBLISH_LOADING_STATUS,
@@ -273,25 +279,32 @@ export const validateOjForm = (props, type) => {
         fetchPostOjForm(paramsObj).then(res => {
           if (res.status === 200) { // 保存成功后,重新跳转至列表页
             if (res.data.status === 0) {
+              // 改变按钮loading状态
+              dispatch({
+                type: types.SUBMIT_LOADING_STATUS,
+                payload: false
+              });
               // message.success(paramsObj['submitType'] === 'update' ? '更新成功' : '保存成功');
               notification.success({
                 message: '提示',
                 description: paramsObj['submitType'] === 'update' ? '更新成功' : '保存成功'
               });
-              linkToDev(dispatch, props);
-            }
-              dispatch({
-                type: types.SUBMIT_LOADING_STATUS,
-                payload: false
+              const {identifier} = res.data;
+              // 保存成功后的identifier
+              identifier && dispatch({
+                type: types.SAVE_OJ_FORM_ID,
+                payload: identifier
               });
+              // 保存或更新后,调用start接口
+              // linkToDev(dispatch, props);
             }
-          }).catch(err => {
-            dispatch({
-              type: types.SUBMIT_LOADING_STATUS,
-              payload: false
-            });
-          }
-        );
+          }}
+        ).catch(err => {
+          dispatch({
+            type: types.SUBMIT_LOADING_STATUS,
+            payload: false
+          });
+        });
       }
     }
   }
@@ -312,7 +325,12 @@ export const handleClickCancelPublish = (props, identifier) => {
             message: '提示',
             description: '撤销发布成功!'
           });
-          linkToDev(dispatch, props);
+          // 改变发布状态值
+          dispatch({
+            type: types.CHANGE_PUBLISH_VALUE,
+            payload: 0
+          });
+          // linkToDev(dispatch, props);
         }
       }
     }).catch(() => {
diff --git a/public/react/src/redux/reducers/commentReducer.js b/public/react/src/redux/reducers/commentReducer.js
new file mode 100644
index 000000000..cf56f1965
--- /dev/null
+++ b/public/react/src/redux/reducers/commentReducer.js
@@ -0,0 +1,42 @@
+import types from "../actions/actionTypes";
+
+/*
+ * @Description: 评论reducer
+ * @Author: tangjiang
+ * @Github: 
+ * @Date: 2019-12-23 10:35:31
+ * @LastEditors  : tangjiang
+ * @LastEditTime : 2019-12-23 14:51:42
+ */
+const initialState = {
+  comments: {
+    content: '' // 评论内容
+  },
+  commentLists: {}, // 评论列表
+  pages: {
+    limit: 20,
+    page: 1
+  }
+};
+
+const commentReducer = (state = initialState, action) => {
+  
+  const { payload, type } = action;
+  switch (type) {
+    case types.ADD_COMMENTS:
+      return {
+        ...state
+      }
+    case types.GET_COMMENT_LISTS:
+      return {
+        ...state,
+        commentLists: Object.assign({}, payload)
+      }
+    default:
+      return {
+        ...state
+      }
+  }
+}
+
+export default commentReducer;
diff --git a/public/react/src/redux/reducers/index.js b/public/react/src/redux/reducers/index.js
index 9c28448a3..206f34384 100644
--- a/public/react/src/redux/reducers/index.js
+++ b/public/react/src/redux/reducers/index.js
@@ -14,6 +14,7 @@ import ojForUserReducer from './ojForUserReducer';
 import commonReducer from './commonReducer';
 import userReducer from './userReducer';
 import jupyterReducer from './jupyterReducer';
+import commentReducer from './commentReducer';
 
 export default combineReducers({
   testReducer,
@@ -22,5 +23,6 @@ export default combineReducers({
   ojForUserReducer,
   commonReducer,
   userReducer,
-  jupyterReducer
+  jupyterReducer,
+  commentReducer
 });
diff --git a/public/react/src/redux/reducers/ojForUserReducer.js b/public/react/src/redux/reducers/ojForUserReducer.js
index 7e3740c19..0950d7442 100644
--- a/public/react/src/redux/reducers/ojForUserReducer.js
+++ b/public/react/src/redux/reducers/ojForUserReducer.js
@@ -3,11 +3,12 @@
  * @Author: tangjiang
  * @Github: 
  * @Date: 2019-11-27 13:41:48
- * @LastEditors: tangjiang
- * @LastEditTime: 2019-12-20 14:46:07
+ * @LastEditors  : tangjiang
+ * @LastEditTime : 2019-12-24 16:35:09
  */
 import types from "../actions/actionTypes";
 import { Base64 } from 'js-base64';
+import actions from "../actions";
 
 const initialState = {
   user_program_identifier: '', // 开启OJ题的唯一标题
@@ -26,6 +27,7 @@ const initialState = {
   notice: false, // 通知
   hadCodeUpdate: false, // 更新代码
   operateType: '', // 点击类型: 调度或提交
+  comment_identifier: '' // 用户评论时使用的 identifier
 };
 
 const ojForUserReducer = (state = initialState, action) => {
@@ -50,7 +52,8 @@ const ojForUserReducer = (state = initialState, action) => {
       return {
         ...state,
         hack: Object.assign({}, hack),
-        test_case: Object.assign({}, test_case)
+        test_case: Object.assign({}, test_case),
+        comment_identifier: hack.identifier
       }
     case types.COMMIT_RECORD_DETAIL:
       let result = action.payload.data;
@@ -179,6 +182,23 @@ const ojForUserReducer = (state = initialState, action) => {
         hadCodeUpdate: false, // 更新代码
         operateType: '', // 点击类型: 调度或提交 
       };
+    // 保存评论时用的 identifer
+    case types.SAVE_COMMENT_IDENTIFIER:
+      return {
+        ...state,
+        comment_identifier: actions.payload
+      };
+    // 是否点赞
+    case types.ADD_OJ_LIKE_COUNT:
+      let _count = state.hack.praises_count;
+      let _user_praise = state.hack.user_praise;
+      _count = +action.payload > 0 ? _count + 1 : _count - 1;
+      _user_praise = +action.payload > 0 ? true : false;
+      const _hack = Object.assign({}, state.hack, {praises_count: _count, user_praise: _user_praise});
+      return {
+        ...state,
+        hack: _hack
+      }
     default:
       return state;
   }
diff --git a/public/react/src/redux/reducers/ojFormReducer.js b/public/react/src/redux/reducers/ojFormReducer.js
index 5e76cabee..43e4c2b3d 100644
--- a/public/react/src/redux/reducers/ojFormReducer.js
+++ b/public/react/src/redux/reducers/ojFormReducer.js
@@ -3,8 +3,8 @@
  * @Author: tangjiang
  * @Github: 
  * @Date: 2019-11-20 16:40:32
- * @LastEditors: tangjiang
- * @LastEditTime: 2019-12-20 16:40:52
+ * @LastEditors  : tangjiang
+ * @LastEditTime : 2019-12-23 10:12:59
  */
 import { Base64 } from 'js-base64';
 import types from '../actions/actionTypes';
@@ -158,9 +158,10 @@ const ojFormReducer = (state = initialState, action) => {
         testCasesValidate: [...tempTestValicate]
       };
     case types.SAVE_OJ_FORM_ID:
-      state.identifier = action.payload;
+      // state.identifier = action.payload;
       return {
-        ...state
+        ...state,
+        identifier: action.payload
       }
     case types.SAVE_EDIT_OJ_FORM_AND_TEST_CASE:  // 保存编辑的值
       /**
@@ -211,6 +212,11 @@ const ojFormReducer = (state = initialState, action) => {
         testCodeStatus: hack_sets.length > 0 ? 'userCase' : 'default',
         isPublish: status
       }
+    case types.CHANGE_PUBLISH_VALUE:
+      return {
+        ...state,
+        isPublish: action.payload
+      };
     case types.CLEAR_JSFORM_STORE:
       state = Object.assign({}, init);
       return {
diff --git a/public/react/src/services/commentService.js b/public/react/src/services/commentService.js
new file mode 100644
index 000000000..47eb347d2
--- /dev/null
+++ b/public/react/src/services/commentService.js
@@ -0,0 +1,45 @@
+/*
+ * @Description: 评论 service
+ * @Author: tangjiang
+ * @Github: 
+ * @Date: 2019-12-23 10:43:27
+ * @LastEditors  : tangjiang
+ * @LastEditTime : 2019-12-24 17:10:49
+ */
+import axios from 'axios';
+
+// 添加评论
+export async function fetchAddComment (identifier, params) {
+  const url = `/problems/${identifier}/comments.json`;
+  return axios.post(url, params);
+}
+
+// 获取评论列表
+export async function fetchCommentLists (identifier) {
+  const url = `/problems/${identifier}/comments.json`;
+  return axios.get(url);
+}
+
+// 添加子评论
+export async function fetchAddChildComment (identifier, params) {
+  const url = `/problems/${identifier}/comments/reply.json`;
+  return axios.post(url, params);
+}
+
+// 删除评论
+export async function fetchDeleteComment (identifier, id) {
+  const url = `/problems/${identifier}/comments/${id}.json`;
+  return axios.delete(url);
+}
+
+// 点赞
+export async function fetchLikeComment (id, params) {
+  const url = `/discusses/${id}/plus.json`;
+  return axios.post(url, params);
+}
+
+// 显示或隐藏
+export async function fetchShowOrHideComment (identifier, id, params) {
+  const url = `/problems/${identifier}/comments/${id}/hidden.json`;
+  return axios.post(url, params);
+}
\ No newline at end of file

From 56f23efd4af73a3e9317a3f43d77cbedd31a9493 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=98=8E?= <775174143@qq.com>
Date: Tue, 24 Dec 2019 17:33:05 +0800
Subject: [PATCH 12/25] =?UTF-8?q?=E8=B0=83=E6=95=B4=E6=8F=90=E7=A4=BA?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 public/react/src/modules/tpm/jupyter/index.js | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/public/react/src/modules/tpm/jupyter/index.js b/public/react/src/modules/tpm/jupyter/index.js
index ad62d249c..7c00a5f6d 100644
--- a/public/react/src/modules/tpm/jupyter/index.js
+++ b/public/react/src/modules/tpm/jupyter/index.js
@@ -146,12 +146,12 @@ function JupyterTPI (props) {
         title: '更新通知',
         content: (<div className="update_notice">
           {stopposttpip(1)}
-          <p className="update_txt">关卡任务的代码文件有更新啦</p>
-          <p className="update_txt">更新操作将保留已完成的评测记录和成绩</p>
-          <p className="update_txt">还未完成评测的任务代码,请自行保存</p>
+          <p className="update_txt">该实训已更新,更新后您编写的实训代码将会丢失</p>
+          <p className="update_txt">如有需要请先导出代码再进行更新</p>
+          {/*<p className="update_txt">还未完成评测的任务代码,请自行保存</p>*/}
         </div>),
-        okText: '确定',
-        cancelText: '取消',
+        okText: '立即更新',
+        cancelText: '稍后再说',
         onOk () {
           syncJupyterCode(myshixun_identifier, '同步成功');
         },onCancel() {

From 79d1acd0164f6d8958919698d79e1880ea29528c Mon Sep 17 00:00:00 2001
From: daiao <358551898@qq.com>
Date: Tue, 24 Dec 2019 17:41:19 +0800
Subject: [PATCH 13/25] =?UTF-8?q?=E9=9A=90=E8=97=8F?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 app/controllers/comments_controller.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/app/controllers/comments_controller.rb b/app/controllers/comments_controller.rb
index c011d53ec..c5d3082ba 100644
--- a/app/controllers/comments_controller.rb
+++ b/app/controllers/comments_controller.rb
@@ -52,7 +52,7 @@ class CommentsController < ApplicationController
   def hidden
     if current_user.admin_or_business?
       @discuss = @hack.discusses.where(id: params[:id]).first
-      @discuss.update_attribute(:hidden, params[:hidden] == "1")
+      @discuss.update_attribute(:hidden, params[:hidden].to_i == 1)
       sucess_status
     else
       Educoder::TipException(403, "..")

From 0d6004562513637b81ead101b8d33989a91b6f6e Mon Sep 17 00:00:00 2001
From: daiao <358551898@qq.com>
Date: Tue, 24 Dec 2019 17:49:44 +0800
Subject: [PATCH 14/25] =?UTF-8?q?fork=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 app/views/shixuns/get_data_sets.json.jbuilder | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/app/views/shixuns/get_data_sets.json.jbuilder b/app/views/shixuns/get_data_sets.json.jbuilder
index 20ced2acd..82ef309f7 100644
--- a/app/views/shixuns/get_data_sets.json.jbuilder
+++ b/app/views/shixuns/get_data_sets.json.jbuilder
@@ -5,7 +5,9 @@ json.data_sets do
     json.author set.author.real_name
     json.created_on set.created_on
     json.filesize number_to_human_size(set.filesize)
-    json.file_path "#{@absolute_folder}/#{set.relative_path_filename}"
+    # 这里需要去除shixunfiles目录后的标识;因为Jupyter代码里面会写死这样的路径,当实训fork后,这个版本库的路径无法修改,因此给用户展示的
+    # 还是/data/shixunfiles/+文件名这种形式
+    json.file_path "#{@absolute_folder}/#{set.relative_path_filename}".gsub("/#{@shixun.identifier}", "")
   end
 end
 json.data_sets_count @data_count
\ No newline at end of file

From d203f8e2460e86205b4870cdc5f0b73f5b8bf2f2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=98=8E?= <775174143@qq.com>
Date: Tue, 24 Dec 2019 18:03:33 +0800
Subject: [PATCH 15/25] =?UTF-8?q?=E8=B0=83=E6=95=B4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 public/react/public/css/edu-all.css                         | 2 +-
 .../react/src/modules/courses/shixunHomework/Challenges.css | 2 +-
 .../react/src/modules/paths/PathDetail/PathDetailIndex.js   | 3 +++
 public/react/src/modules/tpm/TPMIndexHOC.js                 | 6 +++---
 .../modules/tpm/shixunchild/shixunchildCss/Challenges.css   | 2 +-
 public/stylesheets/educoder/edu-all.css                     | 2 +-
 6 files changed, 10 insertions(+), 7 deletions(-)

diff --git a/public/react/public/css/edu-all.css b/public/react/public/css/edu-all.css
index 141f5b8e1..a4cda4c04 100644
--- a/public/react/public/css/edu-all.css
+++ b/public/react/public/css/edu-all.css
@@ -2934,7 +2934,7 @@ a.singlepublishtwo{
     padding: 40px !important;
 }
 .editormd-html-preview{
-    width: 94% !important;
+    width: 100% !important;
     color: #323232 !important;
 }
 #homework_editorMd_description hr{
diff --git a/public/react/src/modules/courses/shixunHomework/Challenges.css b/public/react/src/modules/courses/shixunHomework/Challenges.css
index 2183fd708..8ae2c002c 100644
--- a/public/react/src/modules/courses/shixunHomework/Challenges.css
+++ b/public/react/src/modules/courses/shixunHomework/Challenges.css
@@ -1,5 +1,5 @@
 .editormd-html-preview, .editormd-preview-container {
-    width: 95% !important;
+    width: 100% !important;
 }
 .Finish_button{
     height: 30px;
diff --git a/public/react/src/modules/paths/PathDetail/PathDetailIndex.js b/public/react/src/modules/paths/PathDetail/PathDetailIndex.js
index 7e59b72eb..03f3b9652 100644
--- a/public/react/src/modules/paths/PathDetail/PathDetailIndex.js
+++ b/public/react/src/modules/paths/PathDetail/PathDetailIndex.js
@@ -555,6 +555,9 @@ class PathDetailIndex extends Component{
 							.pathDetailIndex .markdown-body > p {
 								line-height: 28px;
 							}
+							// #shixuns_propaedeutics{
+						  // 	width: 100% !important;
+							// }
 						`
 					}
 				</style>
diff --git a/public/react/src/modules/tpm/TPMIndexHOC.js b/public/react/src/modules/tpm/TPMIndexHOC.js
index cc8e28bf7..f72c4ac94 100644
--- a/public/react/src/modules/tpm/TPMIndexHOC.js
+++ b/public/react/src/modules/tpm/TPMIndexHOC.js
@@ -35,14 +35,14 @@ if (!window['indexHOCLoaded']) {
   // $('head').append($('<link rel="stylesheet" type="text/css" />')
   //     .attr('href', `${_url_origin}/stylesheets/educoder/antd.min.css?1525440977`));
   $('head').append($('<link rel="stylesheet" type="text/css" />')
-      .attr('href', `${_url_origin}/stylesheets/css/edu-common.css?1`));
+      .attr('href', `${_url_origin}/stylesheets/css/edu-common.css?66`));
 
   $('head').append($('<link rel="stylesheet" type="text/css" />')
-      .attr('href', `${_url_origin}/stylesheets/educoder/edu-main.css?1`));
+      .attr('href', `${_url_origin}/stylesheets/educoder/edu-main.css?66`));
 
   // index.html有加载
 	$('head').append($('<link rel="stylesheet" type="text/css" />')
-		.attr('href', `${_url_origin}/stylesheets/educoder/edu-all.css?1`));
+		.attr('href', `${_url_origin}/stylesheets/educoder/edu-all.css?66`));
 
 
   // $('head').append($('<link rel="stylesheet" type="text/css" />')
diff --git a/public/react/src/modules/tpm/shixunchild/shixunchildCss/Challenges.css b/public/react/src/modules/tpm/shixunchild/shixunchildCss/Challenges.css
index 34f71fb1e..83d8fb15d 100644
--- a/public/react/src/modules/tpm/shixunchild/shixunchildCss/Challenges.css
+++ b/public/react/src/modules/tpm/shixunchild/shixunchildCss/Challenges.css
@@ -1,5 +1,5 @@
 .editormd-html-preview, .editormd-preview-container {
-    width: 95% !important;
+    width: 100% !important;
 }
 .Finish_button{
     height: 30px;
diff --git a/public/stylesheets/educoder/edu-all.css b/public/stylesheets/educoder/edu-all.css
index 2832f226f..562ba09c2 100644
--- a/public/stylesheets/educoder/edu-all.css
+++ b/public/stylesheets/educoder/edu-all.css
@@ -2939,7 +2939,7 @@ a.singlepublishtwo{
     padding: 40px !important;
 }
 .editormd-html-preview{
-    width: 94% !important;
+    width:100% !important;
     color: #323232 !important;
 }
 #homework_editorMd_description hr{

From 7ef472177bc694d602bab0ea90772872fc7f907a Mon Sep 17 00:00:00 2001
From: tangjiang <465264938@qq.com>
Date: Tue, 24 Dec 2019 18:18:39 +0800
Subject: [PATCH 16/25] update comment style

---
 .../common/components/comment/CommentIcon.js  |  8 +++--
 .../common/components/comment/CommentItem.js  |  8 +++--
 .../common/components/comment/CommentList.js  | 33 ++++++++++++-------
 .../src/common/components/comment/index.js    |  4 ++-
 .../src/common/components/comment/index.scss  |  8 ++++-
 .../studentStudy/leftpane/comment/index.js    |  6 +++-
 6 files changed, 48 insertions(+), 19 deletions(-)

diff --git a/public/react/src/common/components/comment/CommentIcon.js b/public/react/src/common/components/comment/CommentIcon.js
index ff3b109e1..97a57da5e 100644
--- a/public/react/src/common/components/comment/CommentIcon.js
+++ b/public/react/src/common/components/comment/CommentIcon.js
@@ -4,7 +4,7 @@
  * @Github: 
  * @Date: 2019-12-18 10:49:46
  * @LastEditors  : tangjiang
- * @LastEditTime : 2019-12-24 17:05:14
+ * @LastEditTime : 2019-12-24 18:04:52
  */
 import './index.scss';
 import React from 'react';
@@ -26,7 +26,11 @@ function CommentIcon ({
 
   const _className = [undefined, null, ''].includes(count) ? 'comment_count_none' : 'comment_count';
   return (
-    <span className={`comment_icon_count ${props.className}`} onClick={ handleSpanClick }>
+    <span 
+      style={props.style}
+      className={`comment_icon_count ${props.className}`} 
+      onClick={ handleSpanClick }
+    >
       <Icon className="comment_icon" type={type} style={{ color: iconColor }} theme={theme}/>
       <span className={_className}>{ count }</span>
     </span>
diff --git a/public/react/src/common/components/comment/CommentItem.js b/public/react/src/common/components/comment/CommentItem.js
index 28341a47c..e3a229c50 100644
--- a/public/react/src/common/components/comment/CommentItem.js
+++ b/public/react/src/common/components/comment/CommentItem.js
@@ -4,7 +4,7 @@
  * @Github: 
  * @Date: 2019-12-17 17:35:17
  * @LastEditors  : tangjiang
- * @LastEditTime : 2019-12-24 17:11:59
+ * @LastEditTime : 2019-12-24 18:05:18
  */
 import './index.scss';
 import React, { useState } from 'react';
@@ -14,6 +14,7 @@ import { Icon } from 'antd';
 import CommentForm from './CommentForm';
 
 function CommentItem ({
+  isAdmin,
   options,
   confirm,
   comment,
@@ -60,7 +61,7 @@ function CommentItem ({
   const commentAvatar = (author) => ( 
     <img 
       className="item-flex flex-image" 
-      src={author.image_url ? getImageUrl(`/images/${author.image_url}`) : 'https://b-ssl.duitang.com/uploads/item/201511/13/20151113110434_kyReJ.jpeg'}
+      src={author.image_url ? getImageUrl(`images/${author.image_url}`) : 'https://b-ssl.duitang.com/uploads/item/201511/13/20151113110434_kyReJ.jpeg'}
       alt=""
     />
   );
@@ -175,7 +176,8 @@ function CommentItem ({
         {commentAppend(children)}
 
         <div className="comment_icon_area">
-          <CommentIcon 
+          <CommentIcon
+            style={{ display: isAdmin ? 'inline-block' : 'none'}}
             className='comment-icon-margin' 
             type={!hidden ? "eye" : 'eye-invisible'} 
             iconClick={() => handleShowOrHide(id, !hidden ? 1 : 0)}
diff --git a/public/react/src/common/components/comment/CommentList.js b/public/react/src/common/components/comment/CommentList.js
index dc93bcc10..d2bc1f6ee 100644
--- a/public/react/src/common/components/comment/CommentList.js
+++ b/public/react/src/common/components/comment/CommentList.js
@@ -4,13 +4,15 @@
  * @Github: 
  * @Date: 2019-12-17 17:34:00
  * @LastEditors  : tangjiang
- * @LastEditTime : 2019-12-24 11:30:14
+ * @LastEditTime : 2019-12-24 18:08:07
  */
 import './index.scss';
 import React from 'react';
 import CommentItem from './CommentItem';
+import { Empty } from 'antd';
 function CommentList (props) {
   const {
+    isAdmin,
     commentLists, // 评论列表
     submitChildComment,
     submitDeleteComment,
@@ -21,18 +23,27 @@ function CommentList (props) {
   const {comments = []} = commentLists;
 
   const renderLi = () => {
-    return comments.map((item, index) => {
+    if (comments.length > 0) {
+      return comments.map((item, index) => {
+        return (
+          <CommentItem 
+            isAdmin={isAdmin}
+            key={`item_${index}`}
+            submitChildComment={submitChildComment}
+            submitDeleteComment={submitDeleteComment}
+            comment={item} 
+            likeComment={likeComment}
+            showOrHideComment={showOrHideComment}
+          />
+        );
+      });
+    } else {
       return (
-        <CommentItem 
-          key={`item_${index}`}
-          submitChildComment={submitChildComment}
-          submitDeleteComment={submitDeleteComment}
-          comment={item} 
-          likeComment={likeComment}
-          showOrHideComment={showOrHideComment}
-        />
+        <div className="empty_comment">
+          <Empty />
+        </div>
       );
-    });
+    }
   }
 
   return (
diff --git a/public/react/src/common/components/comment/index.js b/public/react/src/common/components/comment/index.js
index 15e86c980..5efa8c5ad 100644
--- a/public/react/src/common/components/comment/index.js
+++ b/public/react/src/common/components/comment/index.js
@@ -4,7 +4,7 @@
  * @Github: 
  * @Date: 2019-12-17 17:31:33
  * @LastEditors  : tangjiang
- * @LastEditTime : 2019-12-24 15:47:07
+ * @LastEditTime : 2019-12-24 18:03:21
  */
 import React from 'react';
 // import CommentForm from './CommentForm';
@@ -15,6 +15,7 @@ function Comment (props) {
     commentLists,
     // addComment,
     // cancelComment,
+    isAdmin,
     addChildComment,
     likeComment,
     showOrHideComment,
@@ -31,6 +32,7 @@ function Comment (props) {
         onSubmit={addComment}
       /> */}
       <CommentList 
+        isAdmin={isAdmin}
         likeComment={likeComment}
         showOrHideComment={showOrHideComment}
         commentLists={commentLists}
diff --git a/public/react/src/common/components/comment/index.scss b/public/react/src/common/components/comment/index.scss
index 264a5e2aa..2e1dc4880 100644
--- a/public/react/src/common/components/comment/index.scss
+++ b/public/react/src/common/components/comment/index.scss
@@ -9,7 +9,13 @@ $ml: 20px;
 .comment_list_wrapper{
   box-sizing: border-box;
   // border-top: 1px solid $bdColor;
-
+  .empty_comment{
+    display: flex;
+    height: calc(100vh - 200px);
+    width: 100%;
+    justify-content: center;
+    align-items: center;
+  }
   .comment_item_show{
     display: block;
   }
diff --git a/public/react/src/modules/developer/studentStudy/leftpane/comment/index.js b/public/react/src/modules/developer/studentStudy/leftpane/comment/index.js
index 46d7b4e38..2ec70227d 100644
--- a/public/react/src/modules/developer/studentStudy/leftpane/comment/index.js
+++ b/public/react/src/modules/developer/studentStudy/leftpane/comment/index.js
@@ -4,7 +4,7 @@
  * @Github: 
  * @Date: 2019-11-27 09:49:35
  * @LastEditors  : tangjiang
- * @LastEditTime : 2019-12-24 17:10:14
+ * @LastEditTime : 2019-12-24 17:58:26
  */
 import './index.scss';
 import React, { useEffect } from 'react';
@@ -15,6 +15,7 @@ import actions from '../../../../../redux/actions';
 const CommentTask = (props) => {
 
   const {
+    isAdmin,
     identifier,
     commentLists,
     addComment,
@@ -74,6 +75,7 @@ const CommentTask = (props) => {
   return (
     <div className="task_comment_task">
       <Comment 
+        isAdmin={isAdmin}
         commentLists={commentLists}
         addComment={handleAddComment}
         addChildComment={handleAddChildComment}
@@ -92,8 +94,10 @@ const mapStateToProps = (state) => {
   const {
     comment_identifier
   } = state.ojForUserReducer;
+  const { userInfo } = state.userReducer;
   return {
     commentLists,
+    isAdmin: userInfo.admin,
     identifier: comment_identifier
   }
 }

From a4f872bf49dab6ff14e35374bb10e0fb3348637d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=98=8E?= <775174143@qq.com>
Date: Tue, 24 Dec 2019 19:02:58 +0800
Subject: [PATCH 17/25] =?UTF-8?q?=E8=B0=83=E6=95=B4fork?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 public/react/src/modules/tpm/TPMBanner.js | 29 +++++++++++++++++++----
 1 file changed, 25 insertions(+), 4 deletions(-)

diff --git a/public/react/src/modules/tpm/TPMBanner.js b/public/react/src/modules/tpm/TPMBanner.js
index 884efd4c2..73a09bb45 100644
--- a/public/react/src/modules/tpm/TPMBanner.js
+++ b/public/react/src/modules/tpm/TPMBanner.js
@@ -59,7 +59,8 @@ class TPMBanner extends Component {
       openknow:false,
       openshowpublictype:false,
       Radiovalue:1,
-      TextAreaintshow:false
+      TextAreaintshow:false,
+
     }
   }
 
@@ -112,6 +113,15 @@ class TPMBanner extends Component {
 
   componentDidUpdate(prevProps, prevState) {
     if (prevProps != this.props) {
+
+      if(prevProps.user != this.props.user){
+        if(this.props.user&&this.props.user.admin===true||this.props.user&&this.props.user.business===true){
+          this.setState({
+            TextArea:"云上实验室使用"
+          })
+        }
+      }
+
       let shixunopenprocess=window.localStorage.shixunopenprocess;
       let openopenpublictype=window.localStorage.openopenpublictype;
       if(this.props.status===0&&this.props.openknows===false){
@@ -173,8 +183,12 @@ class TPMBanner extends Component {
       })
     }
 
+    if (this.props.user && this.props.user.admin === true || this.props.user && this.props.user.business === true) {
+      this.setState({
+        TextArea: "云上实验室使用"
+      })
+    }
   }
-
   /*
   * Fork
   * */
@@ -736,6 +750,11 @@ class TPMBanner extends Component {
     this.setState({
       Radiovalue:e.target.value
     })
+    if(e.target.value!=4){
+      this.setState({
+        TextAreaintshow:false
+      })
+    }
   }
 
   render() {
@@ -827,7 +846,7 @@ class TPMBanner extends Component {
     };
     //
     // console.log(this.props.shixunsDetails&&this.props.shixunsDetails.is_jupyter)
-    // console.log(this.props)
+ 
     // console.log(this.state)
     return (
 
@@ -1318,7 +1337,9 @@ class TPMBanner extends Component {
                                 其它原因
                               </Radio>
                               {this.state.Radiovalue === 4 ?
-                                <TextArea className={this.state.TextAreaintshow===true?"bor-red mt10":"mt10"} rows={4} style={{ width: '85%', marginLeft: '30px' }} onInput={this.changeTextArea}/>: null}
+                                <TextArea className={this.state.TextAreaintshow===true?"bor-red mt10":"mt10"}
+                                          value={this.state.TextArea}
+                                          rows={4} style={{ width: '85%', marginLeft: '30px' }} onInput={this.changeTextArea}/>: null}
                               {this.state.TextAreaintshow===true?<div className={"color-red ml30"}>不能为空</div>:""}
                             </Radio.Group>
                           </div>

From 971484792650f3c9ae5ed834a424051224eaf4b2 Mon Sep 17 00:00:00 2001
From: daiao <358551898@qq.com>
Date: Tue, 24 Dec 2019 19:32:36 +0800
Subject: [PATCH 18/25] =?UTF-8?q?Jupyter=E5=AE=9E=E8=AE=ADfork=E4=B8=8E?=
 =?UTF-8?q?=E4=BA=91=E4=B8=8A=E5=AE=9E=E9=AA=8C=E5=AE=A4=E9=80=89=E7=94=A8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 app/controllers/shixuns_controller.rb         | 12 +++++++++++
 app/services/subjects/copy_subject_service.rb | 21 ++++++++++++++++++-
 .../result.json.jbuilder                      |  2 +-
 3 files changed, 33 insertions(+), 2 deletions(-)

diff --git a/app/controllers/shixuns_controller.rb b/app/controllers/shixuns_controller.rb
index 190892730..940955e93 100644
--- a/app/controllers/shixuns_controller.rb
+++ b/app/controllers/shixuns_controller.rb
@@ -266,8 +266,20 @@ class ShixunsController < ApplicationController
 				# 如果是jupyter,先创建一个目录,为了挂载(因为后续数据集,开启Pod后环境在没销毁前,你上传数据集是挂载不上目录的,因此要先创建目录,方便中间层挂载)
 				if @new_shixun.is_jupyter?
 					folder = EduSetting.get('shixun_folder')
+					raise "存储目录未定义" unless folder.present?
 					path = "#{folder}/#{@new_shixun.identifier}"
 					FileUtils.mkdir_p(path, :mode => 0777) unless File.directory?(path)
+					# 复制数据集
+					save_path = File.join(folder, @shixun.identifier)
+					@shixun.data_sets.each do |set|
+						new_date_set = Attachment.new
+						new_date_set.attributes = set.attributes.dup.except("id", "container_id", "disk_directory")
+						new_date_set.container_id = @new_shixun.id
+						new_date_set.disk_directory = @new_shixun.identifier
+						new_date_set.save!
+						FileUtils.cp("#{save_path}/#{set.relative_path_filename}", path)
+					end
+
 				end
 				# 同步复制关卡
 				if @shixun.challenges.present?
diff --git a/app/services/subjects/copy_subject_service.rb b/app/services/subjects/copy_subject_service.rb
index f44191fda..4715a8bad 100644
--- a/app/services/subjects/copy_subject_service.rb
+++ b/app/services/subjects/copy_subject_service.rb
@@ -79,7 +79,7 @@ class Subjects::CopySubjectService < ApplicationService
     copy_shixun_service_configs_data!(shixun, to_shixun)
     copy_challenges_data!(shixun, to_shixun)
     copy_shixun_members_data!(to_shixun)
-
+    copy_jupyter_data_sets(shixun, to_shixun) if shixun.is_jupyter?
     # 云上实验室
    if laboratory
      laboratory.laboratory_shixuns.create(shixun: to_shixun)
@@ -87,6 +87,25 @@ class Subjects::CopySubjectService < ApplicationService
     to_shixun
   end
 
+  # 复制jupyter的数据集
+  def copy_jupyter_data_sets(shixun, to_shixun)
+    return unless shixun.is_jupyter?
+    folder = EduSetting.get('shixun_folder')
+    raise "存储目录未定义" unless folder.present?
+    path = "#{folder}/#{to_shixun.identifier}"
+    FileUtils.mkdir_p(path, :mode => 0777) unless File.directory?(path)
+    # 复制数据集
+    save_path = File.join(folder, shixun.identifier)
+    shixun.data_sets.each do |set|
+      new_date_set = Attachment.new
+      new_date_set.attributes = set.attributes.dup.except("id", "container_id", "disk_directory")
+      new_date_set.container_id = to_shixun.id
+      new_date_set.disk_directory = to_shixun.identifier
+      new_date_set.save!
+      FileUtils.cp("#{save_path}/#{set.relative_path_filename}", path)
+    end
+  end
+
   # 创建实训长字段内容
   def copy_shixun_info_data!(shixun, to_shixun)
     to_shixun_info = ShixunInfo.new
diff --git a/app/views/hack_user_lastest_codes/result.json.jbuilder b/app/views/hack_user_lastest_codes/result.json.jbuilder
index 2561d4ecd..d8f010cc3 100644
--- a/app/views/hack_user_lastest_codes/result.json.jbuilder
+++ b/app/views/hack_user_lastest_codes/result.json.jbuilder
@@ -1,5 +1,5 @@
 json.status 0
-json.message "评测成功"
+json.message "评测完成"
 json.data do
   json.(@result, :id, :status, :error_line, :error_msg,
       :input, :output, :execute_time, :execute_memory)

From 19fe97dadee6b4353fc68432348cf8a74e8d7b48 Mon Sep 17 00:00:00 2001
From: daiao <358551898@qq.com>
Date: Tue, 24 Dec 2019 20:15:34 +0800
Subject: [PATCH 19/25] 1

---
 app/controllers/jupyters_controller.rb | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/app/controllers/jupyters_controller.rb b/app/controllers/jupyters_controller.rb
index 988cef01a..2f2591470 100644
--- a/app/controllers/jupyters_controller.rb
+++ b/app/controllers/jupyters_controller.rb
@@ -53,7 +53,8 @@ class JupytersController < ApplicationController
         shixun = Shixun.find_by(identifier: params[:identifier])
         url = jupyter_url_with_shixun(shixun)
         port = jupyter_port_with_shixun(shixun)
-        render json: {status: 0, url: url, port: port}
+        #render json: {status: 0, url: url, port: port}
+        render json: {status: 0}
     end
 
     def reset_with_tpi

From 1347f3c0eb02eaee6931cb887ecb512c1af3bf7a Mon Sep 17 00:00:00 2001
From: daiao <358551898@qq.com>
Date: Tue, 24 Dec 2019 20:20:59 +0800
Subject: [PATCH 20/25] =?UTF-8?q?=E5=9B=9E=E5=A4=8D?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 app/controllers/jupyters_controller.rb | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/app/controllers/jupyters_controller.rb b/app/controllers/jupyters_controller.rb
index 2f2591470..988cef01a 100644
--- a/app/controllers/jupyters_controller.rb
+++ b/app/controllers/jupyters_controller.rb
@@ -53,8 +53,7 @@ class JupytersController < ApplicationController
         shixun = Shixun.find_by(identifier: params[:identifier])
         url = jupyter_url_with_shixun(shixun)
         port = jupyter_port_with_shixun(shixun)
-        #render json: {status: 0, url: url, port: port}
-        render json: {status: 0}
+        render json: {status: 0, url: url, port: port}
     end
 
     def reset_with_tpi

From 3b6daa3d7bd803ed5dc0f529f6045d6421ddcc75 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=98=8E?= <775174143@qq.com>
Date: Wed, 25 Dec 2019 09:28:03 +0800
Subject: [PATCH 21/25] =?UTF-8?q?=E8=B0=83=E6=95=B4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 public/react/src/modules/tpm/TPMBanner.js     |  8 ++++----
 .../modules/tpm/TPMsettings/Configuration.js  |  8 +++++---
 .../tpm/TPMsettings/Shixuninformation.js      |  6 +++++-
 .../modules/tpm/component/TPMRightSection.js  | 14 ++++++-------
 .../src/modules/tpm/component/TPMright.css    |  7 ++++---
 public/react/src/modules/tpm/jupyter/index.js | 12 +++++------
 .../Collaborators/Collaborators.css           | 14 ++++++++-----
 .../Collaborators/Collaborators.js            | 20 +++++++++----------
 .../shixunchild/Ranking_list/Ranking_list.js  |  2 +-
 9 files changed, 51 insertions(+), 40 deletions(-)

diff --git a/public/react/src/modules/tpm/TPMBanner.js b/public/react/src/modules/tpm/TPMBanner.js
index 73a09bb45..fa8a4b222 100644
--- a/public/react/src/modules/tpm/TPMBanner.js
+++ b/public/react/src/modules/tpm/TPMBanner.js
@@ -857,7 +857,7 @@ class TPMBanner extends Component {
               `
               .shixunDetail_top{
                   height: 180px !important;
-                  padding-top:35px !important;
+                  padding-top:50px !important;
               }
               .ant-popover{
                z-index:1000 !important;
@@ -900,9 +900,9 @@ class TPMBanner extends Component {
                 }
 
               </p>
-              <div className="clearfix mt30">
+              <div className="clearfix mt10">
 
-                <ul className="fl color-grey-c pathInfo">
+                <ul className="fl color-grey-c pathInfo mt20">
                   {shixunsDetails&&shixunsDetails.stu_num===0?"":<li>
                     <span>学习人数</span>
                     <span className="mt3">{shixunsDetails.stu_num}</span>
@@ -973,7 +973,7 @@ class TPMBanner extends Component {
                           </div>
                         </div>
                       }>
-                        <div className="pr fl" id="commentsStar">
+                        <div className="pr fl mt15" id="commentsStar">
                           <div className={"color-grey-c  ml15"} style={{color: "#fff", textAlign: "center"}}>学员评分</div>
                           <div className="rateYo">
                             <MyRate allowHalf defaultValue={star_info[0]} disabled/>
diff --git a/public/react/src/modules/tpm/TPMsettings/Configuration.js b/public/react/src/modules/tpm/TPMsettings/Configuration.js
index b65d20f5d..b5aafc909 100644
--- a/public/react/src/modules/tpm/TPMsettings/Configuration.js
+++ b/public/react/src/modules/tpm/TPMsettings/Configuration.js
@@ -295,6 +295,8 @@ export default class Shixuninformation extends Component {
 
     const dateFormat = 'YYYY-MM-DD HH:mm';
 
+    // console.log()
+      console.log(this.props&&this.props.identity<8)
     return (
       <div>
         <div className="educontent mb200 edu-back-white padding10-20 pdb30 mb50">
@@ -308,8 +310,8 @@ export default class Shixuninformation extends Component {
             </span>
           </div>}
 
-          <div className="edu-back-white mb10 ml30 mt20">
-              <div>
+        <div className="edu-back-white mb10 ml30 mt20">
+          {this.props&&this.props.status>1&&this.state.use_scope===0&&this.props&&this.props.identity>7||this.props&&this.props.public===2&&this.state.use_scope===0&&this.props&&this.props.identity>7?"":<div>
                 <span className="color-grey-6 mt5 fl font-16" style={{minWidth: '45px'}}>公开程度:</span>
                 <span className="fl mt8 ml20">
             <RadioGroup onChange={this.SelectOpenpublic} value={this.state.use_scope}>
@@ -387,7 +389,7 @@ export default class Shixuninformation extends Component {
 
 
             </span>
-              </div>
+              </div>}
 
             <div className="clearfix mt20">
               <span className="color-grey-6 mt5 fl font-16" style={{minWidth: '45px'}}>开启时间:</span>
diff --git a/public/react/src/modules/tpm/TPMsettings/Shixuninformation.js b/public/react/src/modules/tpm/TPMsettings/Shixuninformation.js
index 66e1da8dd..04e729596 100644
--- a/public/react/src/modules/tpm/TPMsettings/Shixuninformation.js
+++ b/public/react/src/modules/tpm/TPMsettings/Shixuninformation.js
@@ -1185,7 +1185,11 @@ class Shixuninformation extends Component {
             closable={false}
             footer={null}
           >
-            <div className="task-popup-content"><p className="task-popup-text-center font-16">评测脚本生成成功!</p></div>
+            <div className="task-popup-content">
+              {/*<p className="task-popup-text-center font-16">已根据您的选择,生成新的评测脚本!</p>*/}
+              {/*<p className="task-popup-text-center font-16 mt10">您之前使用的脚本已复制到剪贴板,可通过Ctrl+C贴贴</p>*/}
+              <p className="task-popup-text-center font-16">评测脚本生成成功!</p>
+            </div>
             <div className="task-popup-sure clearfix">
               <a className="task-btn task-btn-orange" onClick={() => this.hidestandard_scriptsModal()}>确定</a>
             </div>
diff --git a/public/react/src/modules/tpm/component/TPMRightSection.js b/public/react/src/modules/tpm/component/TPMRightSection.js
index 88894794b..545032e56 100644
--- a/public/react/src/modules/tpm/component/TPMRightSection.js
+++ b/public/react/src/modules/tpm/component/TPMRightSection.js
@@ -82,18 +82,18 @@ class TPMRightSection extends Component {
                   <div className="flex1">
 
                     <div className="creatorname  sortinxdirection space-between">
-                      <div className={"creatornamelist"}>
+                      <div className={"creatornamelist color-grey-3"}>
                         {TPMRightSectionData === undefined ? "" : TPMRightSectionData.creator === undefined ? "" : TPMRightSectionData.creator.name}
                       </div>
                       <div className={"creatornamelist width80center"}>
-                        {TPMRightSectionData.user_shixuns_count}
+                        <span className={"color888hezuo"}>共发布实训</span> <span className={"color-grey-3"}>{TPMRightSectionData.user_shixuns_count}</span> <span className={"color888hezuo"}>个</span>
                       </div>
                     </div>
-                    <div className="clearfix">
-                      <span className={"fr color888hezuo"}>发布实训项目</span>
-                      {/*<span className="ml20">粉丝 <span id="user_h_fan_count">{TPMRightSectionData.fans_count}</span></span>*/}
-                      {/* <a href="/watchers/unwatch?className=fr+user_watch_btn+edu-default-btn+edu-focus-btn&amp;object_id=3039&amp;object_type=user&amp;shixun_id=61&amp;target_id=3039" className="fr edu-default-btn user_watch_btn edu-focus-btn" data-method="post" data-remote="true" id="cancel_watch" rel="nofollow">取消关注</a> */}
-                    </div>
+                    {/*<div className="clearfix">*/}
+                    {/*  <span className={"fr color888hezuo"}>发布实训项目</span>*/}
+                    {/*  /!*<span className="ml20">粉丝 <span id="user_h_fan_count">{TPMRightSectionData.fans_count}</span></span>*!/*/}
+                    {/*  /!* <a href="/watchers/unwatch?className=fr+user_watch_btn+edu-default-btn+edu-focus-btn&amp;object_id=3039&amp;object_type=user&amp;shixun_id=61&amp;target_id=3039" className="fr edu-default-btn user_watch_btn edu-focus-btn" data-method="post" data-remote="true" id="cancel_watch" rel="nofollow">取消关注</a> *!/*/}
+                    {/*</div>*/}
 
                   </div>
                 </div>
diff --git a/public/react/src/modules/tpm/component/TPMright.css b/public/react/src/modules/tpm/component/TPMright.css
index 0d6b306fd..bef960742 100644
--- a/public/react/src/modules/tpm/component/TPMright.css
+++ b/public/react/src/modules/tpm/component/TPMright.css
@@ -98,14 +98,15 @@
 }
 
 .creatornamelist {
-    -o-text-overflow: ellipsis;
+    cursor: default;
+    overflow: hidden;
     text-overflow: ellipsis;
     white-space: nowrap;
-    cursor: default;
+    width: 139px;
 }
 
 .width80center {
-    width: 80px;
+    font-size:12px;
     text-align: center;
 }
 
diff --git a/public/react/src/modules/tpm/jupyter/index.js b/public/react/src/modules/tpm/jupyter/index.js
index 56b9a4dc3..4485cc1fe 100644
--- a/public/react/src/modules/tpm/jupyter/index.js
+++ b/public/react/src/modules/tpm/jupyter/index.js
@@ -326,12 +326,12 @@ function JupyterTPI (props) {
         </p>
         <p className="jupyter_btn">
            {/*sync | poweroff */}
-          {/*<Button*/}
-          {/*  className="btn_common"*/}
-          {/*  type="link"*/}
-          {/*  icon="history"*/}
-          {/*  onClick={handleClickResetTpi}*/}
-          {/*>重置实训</Button>*/}
+          <Button
+            className="btn_common"
+            type="link"
+            icon="history"
+            onClick={handleClickResetTpi}
+          >重置实训</Button>
 
           <Button
             className="btn_common"
diff --git a/public/react/src/modules/tpm/shixunchild/Collaborators/Collaborators.css b/public/react/src/modules/tpm/shixunchild/Collaborators/Collaborators.css
index b059ab406..075a5af0f 100644
--- a/public/react/src/modules/tpm/shixunchild/Collaborators/Collaborators.css
+++ b/public/react/src/modules/tpm/shixunchild/Collaborators/Collaborators.css
@@ -122,7 +122,7 @@
 }
 .fabushixunwidth{
     color: #000000;
-    font-size: 16px;
+    font-size: 12px;
 }
 .fabushixunwidthcolor{
     color: #4CACFF;
@@ -143,11 +143,11 @@
     height:34px;
     line-height: 34px;
 }
-.hezuozhe630{
-    width: 630px;
+.hezuozhe655{
+    width: 655px;
 }
-.hezuozhe634{
-    width: 634px;
+.hezuozhe655{
+    width: 655px;
 }
 .color333hezuo{
     color:#333333;
@@ -193,4 +193,8 @@
     text-overflow: ellipsis;
     white-space: nowrap;
     cursor: default;
+}
+.centertop20{
+    text-align: center;
+    padding-top: 20%;
 }
\ No newline at end of file
diff --git a/public/react/src/modules/tpm/shixunchild/Collaborators/Collaborators.js b/public/react/src/modules/tpm/shixunchild/Collaborators/Collaborators.js
index a5e055e41..0404bc0fe 100644
--- a/public/react/src/modules/tpm/shixunchild/Collaborators/Collaborators.js
+++ b/public/react/src/modules/tpm/shixunchild/Collaborators/Collaborators.js
@@ -118,6 +118,7 @@ class Collaborators extends Component {
     if (type === "cooperation") {
       this.setState({
         Collaboratorsvisibleadmin: true,
+        Collaboratorsvisible: false,
       });
     } else if ("admin") {
       let id = this.props.match.params.shixunId;
@@ -132,6 +133,7 @@ class Collaborators extends Component {
           } else {
             this.setState({
               Collaboratorsvisible: true,
+              Collaboratorsvisibleadmin: false,
               Collaboratorslist: response.data
             })
           }
@@ -517,17 +519,16 @@ class Collaborators extends Component {
           closable={false}
           footer={null}
         >
-
           <div className="mb15 font-14 edu-txt-center color-orange-tip">
             选择的成员将会成为新的管理员<br/> 您将不再拥有管理员的权限,但您仍是合作团队的一员
           </div>
-
-
           <div className="clearfix mb15 edu-bg-light-blue edu-max-h200">
             <ul className="">
-              <li className="clearfix">
+              <li className={Collaboratorslist&&Collaboratorslist.length===0?"centertop20 clearfix":"clearfix"}>
+                <span>
+                  请先将新的管理员通过 <a className={"color-blue"} onClick={() => this.showCollaboratorsvisible("cooperation")}>"添加合作者"</a> 加入合作者列表
+                </span>
                 <RadioGroup onChange={this.onChange} value={this.state.value}>
-
                   {
                     Collaboratorslist.length === 0 ? "" : Collaboratorslist.map((item, key) => {
                       return (
@@ -536,7 +537,6 @@ class Collaborators extends Component {
                       )
                     })
                   }
-
                 </RadioGroup>
               </li>
             </ul>
@@ -642,7 +642,7 @@ class Collaborators extends Component {
         <style>
           {
             `
-									.collaborators-item-middles{width: 100% !important;    margin-left: 20px;}
+									.collaborators-item-middles{width: 100% !important;}
 									.ysltithead{
 									    padding-bottom: 20px;
 									}
@@ -665,7 +665,7 @@ class Collaborators extends Component {
 
 
                     <div className="fl collaborators-item-middles">
-                      <p className="mb10 sortinxdirection space-between hezuozhe634">
+                      <p className="mb10 sortinxdirection space-between hezuozhe655">
                         <a href={item.user.user_url} target="_blank" className="yslusername">{item.user.name}</a>
                           {item.user.shixun_manager === true ? "" : <span>
                             <i className={this.state.hovertype===true&&key===this.state.hoverkey?"fontnewreds iconfont icon-shanchu_Hover":"fontneweees iconfont icon-shanchu_moren"}
@@ -681,10 +681,10 @@ class Collaborators extends Component {
                       </p>
 
                       <p className="color-grey-B2 font-12 mb10 sortinxdirection mt14">
-                        <p className="hezuozhe630 sortinxdirection space-between">
+                        <p className="hezuozhe655 sortinxdirection space-between">
                           {/*<p className={item.user.identity===null||item.user.identity===undefined||item.user.identity===""?" font-16 ":"mr20 font-16 w70"}>{item.user.identity}</p>*/}
                           <p
-                            className={item.user.school_name === null || item.user.school_name === "" ? "" : " font-16 color888hezuo maxfont450"}>{item.user.school_name}</p>
+                            className={item.user.school_name === null || item.user.school_name === "" ? "" : " font-12 color888hezuo maxfont450"}>{item.user.school_name}</p>
                           <p className="fabushixunwidth color888hezuo">发布实训项目&nbsp;&nbsp;<span
                             className="ml2">{item.user.user_shixuns_count}</span></p>
                         </p>
diff --git a/public/react/src/modules/tpm/shixunchild/Ranking_list/Ranking_list.js b/public/react/src/modules/tpm/shixunchild/Ranking_list/Ranking_list.js
index 0e5d0498b..e1d2d269e 100644
--- a/public/react/src/modules/tpm/shixunchild/Ranking_list/Ranking_list.js
+++ b/public/react/src/modules/tpm/shixunchild/Ranking_list/Ranking_list.js
@@ -129,7 +129,7 @@ class Ranking_list extends Component {
                     {/*<li  className="fl with13 edu-txt-center color-grey-74">*/}
                     {/*/!*{item.accuracy} %准确率*!/*/}
                     {/*</li>*/}
-                    <li  className="fl with25 edu-txt-center">{this.formatSeconds(item.use_time)}</li>
+                    <li  className="fl with25 edu-txt-center">{item.use_time===null?"":this.formatSeconds(item.use_time)}</li>
                     <li  className="fl with14 edu-txt-center color-yellow">+{item.gold}金币 </li>
                   </div>
                 )

From f3308d188ce667394b73594f74768cd2538f94c1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=98=8E?= <775174143@qq.com>
Date: Wed, 25 Dec 2019 09:50:48 +0800
Subject: [PATCH 22/25] =?UTF-8?q?=E8=B0=83=E6=95=B4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 public/react/src/modules/tpm/TPMIndexHOC.js | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/public/react/src/modules/tpm/TPMIndexHOC.js b/public/react/src/modules/tpm/TPMIndexHOC.js
index f72c4ac94..fe760f372 100644
--- a/public/react/src/modules/tpm/TPMIndexHOC.js
+++ b/public/react/src/modules/tpm/TPMIndexHOC.js
@@ -35,14 +35,14 @@ if (!window['indexHOCLoaded']) {
   // $('head').append($('<link rel="stylesheet" type="text/css" />')
   //     .attr('href', `${_url_origin}/stylesheets/educoder/antd.min.css?1525440977`));
   $('head').append($('<link rel="stylesheet" type="text/css" />')
-      .attr('href', `${_url_origin}/stylesheets/css/edu-common.css?66`));
+      .attr('href', `${_url_origin}/stylesheets/css/edu-common.css?8`));
 
   $('head').append($('<link rel="stylesheet" type="text/css" />')
-      .attr('href', `${_url_origin}/stylesheets/educoder/edu-main.css?66`));
+      .attr('href', `${_url_origin}/stylesheets/educoder/edu-main.css?8`));
 
   // index.html有加载
 	$('head').append($('<link rel="stylesheet" type="text/css" />')
-		.attr('href', `${_url_origin}/stylesheets/educoder/edu-all.css?66`));
+		.attr('href', `${_url_origin}/stylesheets/educoder/edu-all.css?8`));
 
 
   // $('head').append($('<link rel="stylesheet" type="text/css" />')

From 2748306d0706781ae2070e37c31fc37cf4c6cd7f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=98=8E?= <775174143@qq.com>
Date: Wed, 25 Dec 2019 09:56:52 +0800
Subject: [PATCH 23/25] =?UTF-8?q?=E8=B0=83=E6=95=B4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../src/modules/tpm/TPMsettings/Shixuninformation.js      | 8 ++++----
 public/react/src/modules/tpm/newshixuns/Newshixuns.js     | 8 ++++----
 2 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/public/react/src/modules/tpm/TPMsettings/Shixuninformation.js b/public/react/src/modules/tpm/TPMsettings/Shixuninformation.js
index 66e1da8dd..0a8220017 100644
--- a/public/react/src/modules/tpm/TPMsettings/Shixuninformation.js
+++ b/public/react/src/modules/tpm/TPMsettings/Shixuninformation.js
@@ -953,10 +953,10 @@ class Shixuninformation extends Component {
                       <div>
                            {this.state.mainvalues === undefined && this.state.subvalues === undefined || this.state.mainvalues === "" && this.state.subvalues === "" ? "" :
                              <div className={"font-12"} style={{'max-width': '600px'}}>
-                               {`${this.state.mainvalues === undefined || this.state.mainvalues === "" ? "" : `已安装软件:` + this.state.mainvalues}`}
-                               {`${this.state.subvalues === undefined || this.state.subvalues === "" ? "" : this.state.mainvalues === undefined || this.state.mainvalues === "" ? `已安装软件:` + this.state.subvalues : this.state.subvalues}`}
-                               {`${this.state.mainvalues === undefined || this.state.mainvalues === "" ? "" : `说明:添加了` + this.state.mainvalues}${this.state.subvalues === undefined || this.state.subvalues === "" ? "" :
-                                 this.state.mainvalues === undefined || this.state.mainvalues === "" ? `说明:添加了` + this.state.subvalues : this.state.subvalues}`}
+                               {`${this.state.mainvalues === undefined || this.state.mainvalues === "" ? "" : this.state.mainvalues}`}
+                               {`${this.state.subvalues === undefined || this.state.subvalues === "" ? "" : this.state.mainvalues === undefined || this.state.mainvalues === "" ? this.state.subvalues : this.state.subvalues}`}
+                               {`${this.state.mainvalues === undefined || this.state.mainvalues === "" ? "" :  this.state.mainvalues}${this.state.subvalues === undefined || this.state.subvalues === "" ? "" :
+                                 this.state.mainvalues === undefined || this.state.mainvalues === "" ? this.state.subvalues : this.state.subvalues}`}
                              </div>}
                       </div>
                 </span>
diff --git a/public/react/src/modules/tpm/newshixuns/Newshixuns.js b/public/react/src/modules/tpm/newshixuns/Newshixuns.js
index 99f8a4377..071b19a5f 100644
--- a/public/react/src/modules/tpm/newshixuns/Newshixuns.js
+++ b/public/react/src/modules/tpm/newshixuns/Newshixuns.js
@@ -620,10 +620,10 @@ class Newshixuns extends Component {
                               <div>
                                 {this.state.mainvalues === undefined && this.state.subvalues === undefined || this.state.mainvalues === "" && this.state.subvalues === "" ? "" :
                                   <div className={"font-12"} style={{'max-width': '600px'}}>
-                                    {`${this.state.mainvalues === undefined || this.state.mainvalues === "" ? "" : `已安装软件:` + this.state.mainvalues}`}
-                                    {`${this.state.subvalues === undefined || this.state.subvalues === "" ? "" : this.state.mainvalues === undefined || this.state.mainvalues === "" ? `已安装软件:` + this.state.subvalues : this.state.subvalues}`}
-                                    {`${this.state.mainvalues === undefined || this.state.mainvalues === "" ? "" : `说明:添加了` + this.state.mainvalues}${this.state.subvalues === undefined || this.state.subvalues === "" ? "" :
-                                      this.state.mainvalues === undefined || this.state.mainvalues === "" ? `说明:添加了` + this.state.subvalues : this.state.subvalues}`}
+                                    {`${this.state.mainvalues === undefined || this.state.mainvalues === "" ? "" : this.state.mainvalues}`}
+                                    {`${this.state.subvalues === undefined || this.state.subvalues === "" ? "" : this.state.mainvalues === undefined || this.state.mainvalues === "" ?  this.state.subvalues : this.state.subvalues}`}
+                                    {`${this.state.mainvalues === undefined || this.state.mainvalues === "" ? "" :   this.state.mainvalues}${this.state.subvalues === undefined || this.state.subvalues === "" ? "" :
+                                      this.state.mainvalues === undefined || this.state.mainvalues === "" ?  this.state.subvalues : this.state.subvalues}`}
                                   </div>}
 
                               </div>

From c6b103ff754db7fa998c093a430c9b20367e7783 Mon Sep 17 00:00:00 2001
From: daiao <358551898@qq.com>
Date: Wed, 25 Dec 2019 10:06:20 +0800
Subject: [PATCH 24/25] =?UTF-8?q?=E6=96=87=E4=BB=B6=E5=A4=B9=E7=9A=84?=
 =?UTF-8?q?=E5=90=8D=E7=A7=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 app/decorators/tiding_decorator.rb            | 3 +++
 app/views/shixuns/get_data_sets.json.jbuilder | 3 ++-
 config/locales/tidings/zh-CN.yml              | 1 +
 3 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/app/decorators/tiding_decorator.rb b/app/decorators/tiding_decorator.rb
index 130e7f4b8..ff198468a 100644
--- a/app/decorators/tiding_decorator.rb
+++ b/app/decorators/tiding_decorator.rb
@@ -250,6 +250,9 @@ module TidingDecorator
     when 'shixunPublish' then
       name = Shixun.find_by(id: parent_container_id)&.name || '---'
       I18n.t(locale_format(parent_container_type)) % [name, container.score]
+    when 'Hack' then
+      name = Hack.find_by(id: container_id)&.name || '---'
+      I18n.t(locale_format(parent_container_type)) % [name, container.score]
     else
       I18n.t(locale_format(parent_container_type)) % container.score
     end
diff --git a/app/views/shixuns/get_data_sets.json.jbuilder b/app/views/shixuns/get_data_sets.json.jbuilder
index 82ef309f7..f800d1c32 100644
--- a/app/views/shixuns/get_data_sets.json.jbuilder
+++ b/app/views/shixuns/get_data_sets.json.jbuilder
@@ -10,4 +10,5 @@ json.data_sets do
     json.file_path "#{@absolute_folder}/#{set.relative_path_filename}".gsub("/#{@shixun.identifier}", "")
   end
 end
-json.data_sets_count @data_count
\ No newline at end of file
+json.data_sets_count @data_count
+json.folder_name @absolute_folder
\ No newline at end of file
diff --git a/config/locales/tidings/zh-CN.yml b/config/locales/tidings/zh-CN.yml
index f484efdc1..dc56ad345 100644
--- a/config/locales/tidings/zh-CN.yml
+++ b/config/locales/tidings/zh-CN.yml
@@ -118,6 +118,7 @@
       Answer:
         true_end: "查看实训%s第%s关的参考答案消耗金币:%s金币"
         false_end: "查看实训的参考答案消耗金币:%s金币"
+      Hack_end: "完成题目解答:%s,获得金币奖励:%s金币"
       Game_end: "通过实训%s的第%s关获得金币奖励:%s金币"
       Memo_end: "发布的评论或者帖子获得平台奖励:%s金币"
       Discusses_end: "发布的评论获得金币奖励:%s金币"

From 71c0b7266b31fc819aa4d056d6a82089235cfc04 Mon Sep 17 00:00:00 2001
From: daiao <358551898@qq.com>
Date: Wed, 25 Dec 2019 10:19:27 +0800
Subject: [PATCH 25/25] =?UTF-8?q?=E5=88=A0=E9=99=A4=E8=AF=84=E8=AE=BA?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 app/views/comments/_discuss.json.jbuilder | 1 +
 app/views/comments/index.json.jbuilder    | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/app/views/comments/_discuss.json.jbuilder b/app/views/comments/_discuss.json.jbuilder
index fed402ffa..55b27acdf 100644
--- a/app/views/comments/_discuss.json.jbuilder
+++ b/app/views/comments/_discuss.json.jbuilder
@@ -12,4 +12,5 @@ if discuss.parent_id
 else
   json.praise_count discuss.praises_count
   json.user_praise discuss.praise_treads.select{|pt| pt.user_id == current_user.id}.length > 0
+  json.can_delete discuss.can_deleted?(current_user) && child.count == 0
 end
\ No newline at end of file
diff --git a/app/views/comments/index.json.jbuilder b/app/views/comments/index.json.jbuilder
index b176d00b9..bfdbdacbb 100644
--- a/app/views/comments/index.json.jbuilder
+++ b/app/views/comments/index.json.jbuilder
@@ -1,6 +1,6 @@
 json.disscuss_count @discusses_count
 json.comments @discusses do |discuss|
-  json.partial! 'comments/discuss', locals: { discuss: discuss}
+  json.partial! 'comments/discuss', locals: { discuss: discuss, child: discuss.child_discuss(current_user)}
   json.children discuss.child_discuss(current_user) do |c_d|
     json.partial! 'comments/discuss', locals: { discuss: c_d }
   end