实训任务详情页面的一级回复功能

This commit is contained in:
daiao 2017-02-21 14:38:05 +08:00
parent e4b582fbb7
commit 544432adce
15 changed files with 217 additions and 75 deletions

View File

@ -29,6 +29,8 @@ class AtController < ApplicationController
case type case type
when "Issue" when "Issue"
find_issue(id) find_issue(id)
whne 'TrainingTask'
find_training_task(id)
when 'Project' when 'Project'
find_project(id) find_project(id)
when 'Course' when 'Course'
@ -69,6 +71,13 @@ class AtController < ApplicationController
at_persons.uniq { |u| u.id }.delete_if { |u| u.id == User.current.id } at_persons.uniq { |u| u.id }.delete_if { |u| u.id == User.current.id }
end end
def find_training_task(id)
training_task = TrainingTask.find(id)
journals = training_task.journals
at_persons = journals.map(&:user) + training_task.project.users
at_persons.uniq { |u| u.id }.delete_if { |u| u.id == User.current.id }
end
def find_project(id) def find_project(id)
return [] if id.to_i<0 return [] if id.to_i<0
at_persons = Project.find(id).users at_persons = Project.find(id).users

View File

@ -88,6 +88,7 @@ class TrainingTasksController < ApplicationController
@journal = Journal.new(:journalized => @training_task) @journal = Journal.new(:journalized => @training_task)
respond_to do |format| respond_to do |format|
format.html format.html
format.js
end end
end end
@ -358,19 +359,19 @@ class TrainingTasksController < ApplicationController
jour = Journal.new jour = Journal.new
jour.user_id = User.current.id jour.user_id = User.current.id
jour.notes = params[:notes] jour.notes = params[:notes]
jour.journalized = @issue jour.journalized = @training_task
jour.save_attachments(params[:attachments]) jour.save_attachments(params[:attachments])
jour.save jour.save
update_user_activity(@issue.class,@issue.id) update_user_activity(@training_task.class, @training_task.id)
update_forge_activity(@issue.class,@issue.id) update_forge_activity(@training_task.class, @training_task.id)
@allowed_statuses = @issue.new_statuses_allowed_to(User.current) # @allowed_statuses = @training_task.new_statuses_allowed_to(User.current)
@user_activity_id = params[:user_activity_id] @user_activity_id = params[:user_activity_id]
@priorities = IssuePriority.active @priorities = IssuePriority.active
respond_to do |format| respond_to do |format|
# Issue详情单独处理 # Issue详情单独处理
if params[:is_issue_show] if params[:is_issue_show]
format.js{redirect_to issue_path(@issue)} format.js{ redirect_to training_task_path(@training_task) }
else else
format.js format.js
end end
@ -397,7 +398,7 @@ class TrainingTasksController < ApplicationController
#对某个journ回复,显示回复框 #对某个journ回复,显示回复框
def reply def reply
@issue = Issue.find(params[:id]) @training_task = TrainingTask.find(params[:id])
@jour = Journal.find(params[:journal_id]) @jour = Journal.find(params[:journal_id])
respond_to do |format| respond_to do |format|
format.js format.js
@ -408,25 +409,25 @@ class TrainingTasksController < ApplicationController
def add_reply def add_reply
if User.current.logged? if User.current.logged?
jour = Journal.find(params[:journal_id]) jour = Journal.find(params[:journal_id])
@issue = Issue.find params[:id] @training_task = TrainingTask.find params[:id]
@project = @issue.project @project = @training_task.project
@allowed_statuses = @issue.new_statuses_allowed_to(User.current) @allowed_statuses = @training_task.new_statuses_allowed_to(User.current)
@priorities = IssuePriority.active @priorities = IssuePriority.active
new_jour = Journal.new new_jour = Journal.new
new_jour.user_id = User.current.id new_jour.user_id = User.current.id
new_jour.reply_id = params[:journal_id] new_jour.reply_id = params[:journal_id]
new_jour.parent_id = jour.id new_jour.parent_id = jour.id
new_jour.notes = params[:content] new_jour.notes = params[:content]
new_jour.journalized = @issue new_jour.journalized = @training_task
new_jour.save_attachments(params[:attachments]) new_jour.save_attachments(params[:attachments])
# new_jour = @issue.journals.build(:user_id => User.current.id, :reply_id => params[:journal_id], :notes => params[:content], :parent_id => jour.id) # new_jour = @issue.journals.build(:user_id => User.current.id, :reply_id => params[:journal_id], :notes => params[:content], :parent_id => jour.id)
@user_activity_id = params[:user_activity_id] @user_activity_id = params[:user_activity_id]
if new_jour.save if new_jour.save
update_user_activity(@issue.class,@issue.id) update_user_activity(@training_task.class,@issue.id)
update_forge_activity(@issue.class,@issue.id) update_forge_activity(@training_task.class,@issue.id)
respond_to do |format| respond_to do |format|
if params[:is_issue_show] if params[:is_issue_show]
format.js{redirect_to issue_path(@issue)} format.js{ redirect_to project_training_task_path(@training_task) }
else else
format.js format.js
end end

View File

@ -1,2 +1,44 @@
module TrainingTasksHelper module TrainingTasksHelper
include ApplicationHelper
include TagsHelper
require 'iconv'
# Returns the textual representation of a journal details
# as an array of strings
def details_to_strings(details, no_html=false, options={})
options[:only_path] = (options[:only_path] == false ? false : true)
options[:token] = options[:token] if options[:token]
strings = []
values_by_field = {}
details.each do |detail|
if detail.property == 'cf'
field_id = detail.prop_key
field = CustomField.find_by_id(field_id)
if field && field.multiple?
values_by_field[field_id] ||= {:added => [], :deleted => []}
if detail.old_value
values_by_field[field_id][:deleted] << detail.old_value
end
if detail.value
values_by_field[field_id][:added] << detail.value
end
next
end
end
strings << show_detail(detail, no_html, options)
end
values_by_field.each do |field_id, changes|
detail = JournalDetail.new(:property => 'cf', :prop_key => field_id)
if changes[:added].any?
detail.value = changes[:added]
strings << show_detail(detail, no_html, options)
elsif changes[:deleted].any?
detail.old_value = changes[:deleted]
strings << show_detail(detail, no_html, options)
end
end
strings
end
end end

View File

@ -23,7 +23,8 @@ class Journal < ActiveRecord::Base
belongs_to :journalized, :polymorphic => true,:touch => true belongs_to :journalized, :polymorphic => true,:touch => true
# added as a quick fix to allow eager loading of the polymorphic association # added as a quick fix to allow eager loading of the polymorphic association
# since always associated to an issue, for now # since always associated to an issue, for now
belongs_to :issue, :foreign_key => :journalized_id,:touch => true belongs_to :issue, :foreign_key => :journalized_id, :touch => true
belongs_to :training_task, :foreign_key => :journalized_id, :touch => true
belongs_to :user belongs_to :user
has_many :details, :class_name => "JournalDetail", :dependent => :delete_all has_many :details, :class_name => "JournalDetail", :dependent => :delete_all
@ -192,6 +193,7 @@ class Journal < ActiveRecord::Base
def act_as_forge_message def act_as_forge_message
receivers = [] receivers = []
# 直接回复 # 直接回复
if self.journalized_type == 'Issue'
if self.user_id != self.issue.author_id if self.user_id != self.issue.author_id
receivers << self.issue.author_id receivers << self.issue.author_id
end end
@ -201,10 +203,19 @@ class Journal < ActiveRecord::Base
receivers.each do |r| receivers.each do |r|
self.forge_messages << ForgeMessage.new(:user_id => r, :project_id => self.issue.project_id, :viewed => false) self.forge_messages << ForgeMessage.new(:user_id => r, :project_id => self.issue.project_id, :viewed => false)
end end
elsif self.journalized_type == 'TrainingTask'
if self.user_id != self.training_task.author_id
receivers << self.training_task.author_id
end
receivers.each do |r|
self.forge_messages << ForgeMessage.new(:user_id => r, :project_id => self.training_task.project, :viewed => false)
end
end
end end
# 更新用户分数 -by zjc # 更新用户分数 -by zjc
def be_user_score def be_user_score
if (self.journalized_type == 'Issue')
#新建了缺陷留言且留言不为空,不为空白 #新建了缺陷留言且留言不为空,不为空白
if !self.notes.nil? && self.notes.gsub(' ','') != '' if !self.notes.nil? && self.notes.gsub(' ','') != ''
#协同得分加分 #协同得分加分
@ -212,7 +223,14 @@ class Journal < ActiveRecord::Base
update_messges_for_issue(self.user,1) update_messges_for_issue(self.user,1)
update_messges_for_issue(self.user,2,self.issue.project) update_messges_for_issue(self.user,2,self.issue.project)
end end
elsif( self.journalized_type == 'TrainingTask')
if !self.notes.nil? && self.notes.gsub(' ','') != ''
#协同得分加分
UserScore.joint(:post_issue_message, self.user, self.training_task.author, self, { message_id: self.id })
update_messges_for_issue(self.user, 1)
update_messges_for_issue(self.user, 2, self.training_task.project)
end
end
end end
# 减少用户分数 -by zjc # 减少用户分数 -by zjc
def down_user_score def down_user_score
@ -237,12 +255,18 @@ class Journal < ActiveRecord::Base
# issue留言总数更新 # issue留言总数更新
def add_journals_count def add_journals_count
if self.journalized_type == 'Issue'
if !self.issue.project.nil? && self.journalized_type == "Issue" && !self.issue.project.project_score.nil? if !self.issue.project.nil? && self.journalized_type == "Issue" && !self.issue.project.project_score.nil?
project = self.issue.project project = self.issue.project
project.project_score.update_attribute(:issue_journal_num, project.project_score.issue_journal_num + 1) project.project_score.update_attribute(:issue_journal_num, project.project_score.issue_journal_num + 1)
end end
elsif self.journalized_type == 'TrainingTask'
if !self.training_task.project.nil? && self.journalized_type == "TrainingTask" && !self.training_task.project.project_score.nil?
project = self.training_task.project
project.project_score.update_attribute(:issue_journal_num, project.project_score.issue_journal_num + 1)
end
end
end end
# 回复issue的时候更新issue的时候 # 回复issue的时候更新issue的时候
def update_issue_time def update_issue_time
if self.journalized_type == "Issue" if self.journalized_type == "Issue"

View File

@ -1,11 +1,23 @@
<% if PraiseTread.praised(activity) %> <% if PraiseTread.praised(activity) %>
<a href='<%= praise_tread_praise_plus_path({:obj_id=>activity.id,:obj_type=>activity.class,:user_activity_id=>user_activity_id,:type=>type }) %>' data-remote="true" class="<%=type == 'reply'? 'fr' : 'ml15' %> likeButton" title="点赞" > <a href='<%= praise_tread_praise_plus_path({:obj_id => activity.id,
:obj_type => activity.class,
:user_activity_id => user_activity_id,
:type => type }) %>'
data-remote="true"
class="<%= type == 'reply'? 'fr' : 'ml15' %> likeButton"
title="点赞" >
<span class="likeText">赞</span> <span class="likeText">赞</span>
<% num = activity.praise_tread_cache ? activity.praise_tread_cache.praise_num : 0 %> <% num = activity.praise_tread_cache ? activity.praise_tread_cache.praise_num : 0 %>
<span class="likeNum"><%= (num.nil? ? 0 : num) > 0 ? "#{(num.nil? ? 0 : num)}" : "" %></span> <span class="likeNum"><%= (num.nil? ? 0 : num) > 0 ? "#{(num.nil? ? 0 : num)}" : "" %></span>
</a> </a>
<% else %> <% else %>
<a href='<%= praise_tread_praise_minus_path({:obj_id=>activity.id,:obj_type=>activity.class,:user_activity_id=>user_activity_id,:type=>type }) %>' data-remote="true" class="<%=type == 'reply'? 'fr' : 'ml15' %> likeButton" title="取消点赞" > <a href='<%= praise_tread_praise_minus_path({:obj_id => activity.id,
:obj_type => activity.class,
:user_activity_id => user_activity_id,
:type => type }) %>'
data-remote="true"
class="<%= type == 'reply'? 'fr' : 'ml15' %> likeButton"
title="取消点赞" >
<span class="likeText">已赞</span> <span class="likeText">已赞</span>
<% num = activity.praise_tread_cache ? activity.praise_tread_cache.praise_num : 0 %> <% num = activity.praise_tread_cache ? activity.praise_tread_cache.praise_num : 0 %>
<span class="likeNum"><%= (num.nil? ? 0 : num) > 0 ? "#{(num.nil? ? 0 : num)}" : "" %></span> <span class="likeNum"><%= (num.nil? ? 0 : num) > 0 ? "#{(num.nil? ? 0 : num)}" : "" %></span>

View File

@ -4,19 +4,7 @@
</div> </div>
<div class="talk_txt fl"> <div class="talk_txt fl">
<p class="pro_page_tit" style="word-break:break-all;"> <p class="pro_page_tit" style="word-break:break-all;">
<% case @training_task.tracker_id %> <span style="padding-left: 5px;"><%= @training_task.subject %></span></p>
<% when 1%>
<span class="fl" title="缺陷">【缺陷】</span>
<% when 2%>
<span class="fl" title="功能">【功能】</span>
<% when 3%>
<span class="fl" title="支持">【支持】</span>
<% when 4%>
<span class="fl" title="任务">【任务】</span>
<% when 5%>
<span class="fl" title="周报">【周报】</span>
<% end %>
</span> <span style="padding-left: 5px;"><%= @training_task.subject %></span></p>
<!--<span class='<%#= "#{get_issue_priority(@training_task.priority_id)[0]} " %>'><%#= get_issue_priority(@training_task.priority_id)[1] %></span></p>--> <!--<span class='<%#= "#{get_issue_priority(@training_task.priority_id)[0]} " %>'><%#= get_issue_priority(@training_task.priority_id)[1] %></span></p>-->
<br> <br>
<div class="cl"></div> <div class="cl"></div>
@ -38,8 +26,8 @@
<% end -%> <% end -%>
<%# 附件局部刷新 %> <%# 附件局部刷新 %>
<div id = "div_issue_attachment_<%=@training_task.id %>"> <div id = "div_issue_attachment_<%= @training_task.id %>">
<%= render :partial => 'task_attachments',:locals => {:training_task => @training_task} %> <%= render :partial => 'task_attachments', :locals => {:training_task => @training_task} %>
</div> </div>
<!--属性--> <!--属性-->
<%#= render :partial => 'issues/attributes_show' %> <%#= render :partial => 'issues/attributes_show' %>

View File

@ -10,7 +10,7 @@
<div class="homepagePostReplyPortrait" > <div class="homepagePostReplyPortrait" >
<%= link_to image_tag(url_to_avatar(comment.user), :width => "33", :height => "33"), user_path(comment.user_id), :alt => "用户头像" %> <%= link_to image_tag(url_to_avatar(comment.user), :width => "33", :height => "33"), user_path(comment.user_id), :alt => "用户头像" %>
</div> </div>
<div class="reply-content ml15" onmouseover="$('#delete_reply_<%=comment.id %>').show();" onmouseout="$('#delete_reply_<%=comment.id %>').hide();"> <div class="reply-content ml15" onmouseover="$('#delete_reply_<%= comment.id %>').show();" onmouseout="$('#delete_reply_<%= comment.id %>').hide();">
<%= render :partial => 'users/news_contents', :locals => {:comment => comment, :type => 'Issue', :user_activity_id => issue.id}%> <%= render :partial => 'users/news_contents', :locals => {:comment => comment, :type => 'Issue', :user_activity_id => issue.id}%>
<div class="homepagePostReplyContent break_word list_style upload_img table_maxWidth" id="reply_content_<%= comment.id %>"> <div class="homepagePostReplyContent break_word list_style upload_img table_maxWidth" id="reply_content_<%= comment.id %>">
@ -28,17 +28,22 @@
<%= render :partial => "praise_tread/praise", :locals => {:activity => comment, :user_activity_id => comment.id, :type => "reply"} %> <%= render :partial => "praise_tread/praise", :locals => {:activity => comment, :user_activity_id => comment.id, :type => "reply"} %>
</span> </span>
<span style="position: relative" class="fr mr20"> <span style="position: relative" class="fr mr20">
<%= link_to( <%= link_to(l(:button_reply),
l(:button_reply), {:controller => 'training_tasks',
{:controller => 'training_tasks', :action => 'reply', :user_id => comment.user_id, :id => issue.id, :journal_id => comment.id}, :action => 'reply',
:user_id => comment.user_id,
:id => @training_task.id,
:journal_id => comment.id},
:remote => true, :remote => true,
:method => 'get', :method => 'get',
:title => l(:button_reply)) %> :title => l(:button_reply)) %>
<span id="reply_iconup_<%= comment.id %>" class="reply_iconup02" style="display: none"> ︿</span> <span id="reply_iconup_<%= comment.id %>" class="reply_iconup02" style="display: none"> ︿</span>
</span> </span>
<%= link_to( <%= link_to(l(:button_delete),
l(:button_delete), {:controller => 'training_tasks',
{:controller => 'training_tasks',:action => 'delete_journal', :id => issue.id, :journal_id=>comment.id}, :action => 'delete_journal',
:id => @training_task.id,
:journal_id=>comment.id},
:method => :get, :method => :get,
:remote => true, :remote => true,
:id => "delete_reply_#{comment.id}", :id => "delete_reply_#{comment.id}",
@ -50,7 +55,7 @@
<div class="cl"></div> <div class="cl"></div>
</div> </div>
</div> </div>
<p id="reply_message_<%= comment.id%>"></p> <p id="reply_message_<%= comment.id %>"></p>
</div> </div>
<div class="cl"></div> <div class="cl"></div>
</li> </li>

View File

@ -1,5 +1,6 @@
<% count = @training_task.journals.count %> <% count = @training_task.journals.count %>
回复<sapn class="mr15"><%= count>0 ? "#{count}" : "" %></sapn><span style="color: #cecece;">▪</span> 回复<span class="mr15"><%= count > 0 ? "#{count}" : "" %></span>
<span style="color: #cecece;">▪</span>
<span id="praise_count_<%= @training_task.id %>"> <span id="praise_count_<%= @training_task.id %>">
<%=render :partial=> "praise_tread/praise", :locals => {:activity => @training_task, :user_activity_id=> @training_task.id, :type => "activity"}%> <%=render :partial => "praise_tread/praise", :locals => {:activity => @training_task, :user_activity_id => @training_task.id, :type => "activity"}%>
</span> </span>

View File

@ -0,0 +1,27 @@
<div class="ReplyToMessageContainer borderBottomNone " id="reply_to_message_<%= @jour.id %>" style="width:895px;">
<div class="homepagePostReplyPortrait mr15 imageFuzzy" id="reply_image_<%= @jour.id%>">
<%= link_to image_tag(url_to_avatar(User.current), :width => "33", :height => "33"), user_path(@training_task.author_id), :alt => "用户头像" %>
</div>
<div class="ReplyToMessageInputContainer">
<% if User.current.logged? %>
<div nhname='new_message_<%= @jour.id %>' style="display:none;">
<%= form_for('new_form',:url => add_reply_training_tasks_path(@training_task.id, :is_issue_show => true),:method => "post", :remote => true) do |f|%>
<input type="hidden" name="journal_id" value="<%= @jour.id %>"/>
<div nhname='toolbar_container_<%= @jour.id %>' ></div>
<div class="cl"></div>
<textarea placeholder="有问题或有建议,请直接给我留言吧!" style="display: none" nhname='new_message_textarea_<%= @jour.id%>' name="content"></textarea>
<div class="cl"></div>
<span nhname='contentmsg_<%= @jour.id %>' class="fl"></span>
<a id="new_message_submit_btn_<%= @jour.id %>" href="javascript:void(0)" onclick="this.style.display='none'" class="blue_n_btn fr" style="display:none;margin-top:6px;">发送</a>
<div class="cl"></div>
<% end %>
</div>
<% else %>
<%= render :partial => "users/show_unlogged" %>
<% end %>
<div class="cl"></div>
</div>
</div>

View File

@ -0,0 +1 @@

View File

@ -0,0 +1,8 @@
if($("#reply_message_<%= @jour.id %>").length > 0) {
$("#reply_message_<%= @jour.id %>").replaceWith("<%= escape_javascript(render :partial => 'training_tasks/training_tasks_reply_ke_form') %>");
$(function(){
sd_create_editor_from_data(<%= @jour.id %>, null, "100%", "<%= @jour.class.name %>");
});
}else if($("#reply_to_message_<%= @jour.id %>").length >0) {
$("#reply_to_message_<%= @jour.id %>").replaceWith("<p id='reply_message_<%= @jour.id %>'></p>");
}

View File

@ -3,13 +3,13 @@
<%= javascript_include_tag 'create_kindeditor'%> <%= javascript_include_tag 'create_kindeditor'%>
<% end %> <% end %>
<script> <script>
sd_create_editor_from_data(<%= @training_task.id%>, null, "100%", "<%= @training_task.class.name %>"); sd_create_editor_from_data(<%= @training_task.id %>, null, "100%", "<%= @training_task.class.name %>");
</script> </script>
<div class="mt10 mb10" id =issue_show_total""> <div class="mt10 mb10" id =issue_show_total"">
<div class="banner-big f16 fontGrey3"> <div class="banner-big f16 fontGrey3">
任务详情 任务详情
<a href="<%= new_project_training_task_path(@project)%>" class="sy_btn_green fr" >新建</a> <a href="<%= new_project_training_task_path(@project) %>" class="sy_btn_green fr" >新建</a>
</div> </div>
<div class="container-big mt10" style="float:left;"> <div class="container-big mt10" style="float:left;">
@ -23,15 +23,15 @@
<!--problem_main end--> <!--problem_main end-->
<div style="clear: both;"></div> <div style="clear: both;"></div>
<div class="container-big-grey"> <div class="container-big-grey">
<div class="topBorder" style="display: <%= @training_task.journals.count>0 ? 'none': '' %>"></div> <div class="topBorder" style="display: <%= @training_task.journals.count > 0 ? 'none': '' %>"></div>
<div class="reply-banner" > <div class="reply-banner" >
<div class="homepagePostReplyBannerCount"> <div class="homepagePostReplyBannerCount" id="training_task_reply_banner">
<%=render :partial => 'reply_banner' %> <%= render :partial => 'reply_banner' %>
</div> </div>
<div class="homepagePostReplyBannerTime"></div> <div class="homepagePostReplyBannerTime"></div>
</div> </div>
<div class="" id="reply_div_<%= @training_task.id %>" > <div class="" id="reply_div_<%= @training_task.id %>" >
<%= render :partial => 'issue_replies',:locals => {:issue => @training_task, :replies_all_i => 0} %> <%= render :partial => 'issue_replies',:locals => {:issue => @training_task, :replies_all_i => 0 } %>
</div> </div>
</div> </div>
</div> </div>

View File

@ -0,0 +1,19 @@
// $("#div_user_issue_reply_<%#= @user_activity_id %>").html("<%#= escape_javascript(render :partial => 'projects/project_issue_reply', :locals => {:activity => @issue, :user_activity_id => @user_activity_id}) %>");
$("#reply_div_<%= @training_task.id %>").html("<%= escape_javascript(render :partial => 'training_tasks/issue_replies', :locals => {:issue => @training_task}) %>");
$("#div_issue_attachment_<%=@training_task.id %>").html("<%= escape_javascript(render :partial => 'issues/issue_attachments', :locals => {:issue => @training_task}) %>");
issue_desc_editor = KindEditor.create('#issue_description',
{"width":"85%",
"resizeType":0,
"no_label":true,
"at_id":<%= @training_task.project_id%>,
"at_type":"Project",
"autoHeightMode":true,
"afterCreate":"eval(function(){ if(typeof enablePasteImg ==='function'){enablePasteImg(self);};if(typeof enableAt ==='function'){enableAt(self, \"<%= @training_task.project_id %>\", 'Project');}; this.loadPlugin('autoheight')})",
"emotionsBasePath":'<%= Setting.host_name%>',
"height":300,
"allowFileManager":true,
"uploadJson":"/kindeditor/upload",
"fileManagerJson":"/kindeditor/filemanager"});
$(".homepagePostReplyBannerCount").html('<%= escape_javascript(render :partial => 'reply_banner') %>');
sd_create_editor_from_data(<%= @training_task.id %>, null, "100%", "<%= @training_task.class.name %>");

View File

@ -1099,6 +1099,11 @@ RedmineApp::Application.routes.draw do
post 'complete_training_task' post 'complete_training_task'
end end
collection do collection do
post 'add_journal'
post 'add_journal_in_org'
get 'delete_journal'
get 'reply'
post 'add_reply'
end end
end end