| @@ -1,32 +1,67 @@ | |||||
| class Api::V1::Issues::MilestonesController < Api::V1::BaseController | class Api::V1::Issues::MilestonesController < Api::V1::BaseController | ||||
| before_action :require_public_and_member_above, only: [:index] | |||||
| before_action :require_public_and_member_above | |||||
| before_action :load_milestone, only: [:show, :update, :destroy] | |||||
| # 里程碑列表 | # 里程碑列表 | ||||
| def index | def index | ||||
| if params[:only_name] | if params[:only_name] | ||||
| @milestones = @project.versions | |||||
| @milestones = @project.versions.select(:id, :name) | |||||
| @milestones = @milestones.ransack(name_or_description_cont: params[:keyword]).result if params[:keyword].present? | |||||
| @milestones = kaminary_select_paginate(@milestones) | |||||
| else | else | ||||
| @milestones = @project.versions.includes(:issues) | |||||
| @milestones = @project.versions.includes(:issues, :closed_issues, :opened_issues) | |||||
| @milestones = params[:category] == "closed" ? @milestones.closed : @milestones.opening | |||||
| @milestones = @milestones.ransack(name_or_description_cont: params[:keyword]).result if params[:keyword].present? | |||||
| @milestones = kaminari_paginate(@milestones) | |||||
| end | end | ||||
| @milestones = @milestones.ransack(name_or_description_cont: params[:keyword]).result if params[:keyword].present? | |||||
| @milestones = kaminary_select_paginate(@milestones) | |||||
| end | end | ||||
| # 里程碑详情 | |||||
| def show | |||||
| def create | |||||
| @milestone = @project.versions.new(milestone_params) | |||||
| if @milestone.save! | |||||
| render_ok | |||||
| else | |||||
| render_error(@milestone.errors.full_messages.join(",")) | |||||
| end | |||||
| end | end | ||||
| def create | |||||
| # 里程碑详情 | |||||
| def show | |||||
| @object_results = Api::V1::Issues::Milestones::DetailIssuesService.call(@project, @milestone, query_params, current_user) | |||||
| @closed_issues_count = @object_results.closed.size | |||||
| @opened_issues_count = @object_results.opened.size | |||||
| @issues = kaminari_paginate(@object_results) | |||||
| end | end | ||||
| def update | def update | ||||
| @milestone.attributes = milestone_params | |||||
| if @milestone.save! | |||||
| render_ok | |||||
| else | |||||
| render_error(@milestone.errors.full_messages.join(",")) | |||||
| end | |||||
| end | end | ||||
| def destroy | def destroy | ||||
| if @milestone.destroy! | |||||
| render_ok | |||||
| else | |||||
| render_error("删除里程碑失败!") | |||||
| end | |||||
| end | end | ||||
| private | private | ||||
| def milestone_params | |||||
| params.permit(:name, :description, :effective_date) | |||||
| end | |||||
| def query_params | |||||
| params.permit(:category, :author_id, :assigner_id, :sort_by, :sort_direction, :issue_tag_ids => []) | |||||
| end | |||||
| def load_milestone | |||||
| @milestone = @project.versions.find_by_id(params[:id]) | |||||
| return render_not_found('里程碑不存在!') unless @milestone.present? | |||||
| end | |||||
| end | end | ||||
| @@ -28,6 +28,9 @@ class Version < ApplicationRecord | |||||
| has_many :issues, class_name: "Issue", foreign_key: "fixed_version_id" | has_many :issues, class_name: "Issue", foreign_key: "fixed_version_id" | ||||
| belongs_to :user, optional: true | belongs_to :user, optional: true | ||||
| has_many :opened_issues, -> {where(issue_classify: "Issue").where.not(status_id: 5)}, class_name: "Issue", foreign_key: :fixed_version_id | |||||
| has_many :closed_issues, -> {where(issue_classify: "Issue", status_id: 5)}, class_name: "Issue", foreign_key: :fixed_version_id | |||||
| scope :version_includes, ->{includes(:issues, :user)} | scope :version_includes, ->{includes(:issues, :user)} | ||||
| scope :closed, ->{where(status: 'closed')} | scope :closed, ->{where(status: 'closed')} | ||||
| scope :opening, ->{where(status: 'open')} | scope :opening, ->{where(status: 'open')} | ||||
| @@ -43,6 +46,11 @@ class Version < ApplicationRecord | |||||
| after_create :send_create_message_to_notice_system | after_create :send_create_message_to_notice_system | ||||
| after_save :send_update_message_to_notice_system | after_save :send_update_message_to_notice_system | ||||
| def issue_percent | |||||
| issues_total_count = opened_issues.size + closed_issues.size | |||||
| issues_total_count.zero? ? 0.0 : closed_issues.size.to_f / issues_total_count | |||||
| end | |||||
| def version_user | def version_user | ||||
| User.select(:login, :lastname,:firstname, :nickname)&.find_by_id(self.user_id) | User.select(:login, :lastname,:firstname, :nickname)&.find_by_id(self.user_id) | ||||
| end | end | ||||
| @@ -53,6 +61,6 @@ class Version < ApplicationRecord | |||||
| end | end | ||||
| def send_update_message_to_notice_system | def send_update_message_to_notice_system | ||||
| SendTemplateMessageJob.perform_later('ProjectMilestoneCompleted', self.id) if Site.has_notice_menu? && self.percent == 1.0 | |||||
| SendTemplateMessageJob.perform_later('ProjectMilestoneCompleted', self.id) if Site.has_notice_menu? && self.issue_percent == 1.0 | |||||
| end | end | ||||
| end | end | ||||
| @@ -20,7 +20,9 @@ class Api::V1::Issues::BatchUpdateService < ApplicationService | |||||
| raise Error, errors.full_messages.join(", ") unless valid? | raise Error, errors.full_messages.join(", ") unless valid? | ||||
| ActiveRecord::Base.transaction do | ActiveRecord::Base.transaction do | ||||
| @issues.each do |issue| | @issues.each do |issue| | ||||
| Api::V1::Issues::UpdateService.call(project, issue, params, current_user) | |||||
| if issue.issue_classify == "Issue" | |||||
| Api::V1::Issues::UpdateService.call(project, issue, params, current_user) | |||||
| end | |||||
| end | end | ||||
| return true | return true | ||||
| @@ -0,0 +1,59 @@ | |||||
| class Api::V1::Issues::Milestones::DetailIssuesService < ApplicationService | |||||
| include ActiveModel::Model | |||||
| attr_reader :project, :category, :author_id, :assigner_id, :issue_tag_ids, :sort_by, :sort_direction, :current_user | |||||
| attr_accessor :queried_issues | |||||
| validates :category, inclusion: {in: %w(all opened closed), message: "请输入正确的Category"} | |||||
| validates :sort_by, inclusion: {in: Issue.column_names, message: '请输入正确的SortBy'}, allow_blank: true | |||||
| validates :sort_direction, inclusion: {in: %w(asc desc), message: '请输入正确的SortDirection'}, allow_blank: true | |||||
| validates :current_user, presence: true | |||||
| def initialize(project, milestone, params, current_user=nil) | |||||
| @project = project | |||||
| @milestone = milestone | |||||
| @category = params[:category] || 'all' | |||||
| @author_id = params[:author_id] | |||||
| @assigner_id = params[:assigner_id] | |||||
| @issue_tag_ids = params[:issue_tag_ids] | |||||
| @sort_by = params[:sort_by].present? ? params[:sort_by] : 'updated_on' | |||||
| @sort_direction = (params[:sort_direction].present? ? params[:sort_direction] : 'desc').downcase | |||||
| @current_user = current_user | |||||
| end | |||||
| def call | |||||
| raise Error, errors.full_messages.join(", ") unless valid? | |||||
| begin | |||||
| issue_query_data | |||||
| queried_issues | |||||
| rescue | |||||
| raise Error, "服务器错误,请联系系统管理员!" | |||||
| end | |||||
| end | |||||
| private | |||||
| def issue_query_data | |||||
| issues = @milestone.issues.issue_issue | |||||
| case category | |||||
| when 'closed' | |||||
| issues = issues.closed | |||||
| when 'opened' | |||||
| issues = issues.opened | |||||
| end | |||||
| # author_id | |||||
| issues = issues.where(author_id: author_id) if author_id.present? | |||||
| # assigner_id | |||||
| issues = issues.joins(:assigners).where(users: {id: assigner_id}).or(issues.where(assigned_to_id: assigner_id)) if assigner_id.present? | |||||
| scope = issues.includes(:priority, :issue_status, :user, :assigners, :version, :issue_tags, :comment_journals) | |||||
| scope = scope.reorder("issues.#{sort_by} #{sort_direction}").distinct | |||||
| @queried_issues = scope | |||||
| end | |||||
| end | |||||
| @@ -0,0 +1,6 @@ | |||||
| json.(milestone, :id, :name, :description, :effective_date, :status) | |||||
| json.issues_count milestone.opened_issues.size + milestone.closed_issues.size | |||||
| json.close_issues_count milestone.closed_issues.size | |||||
| json.percent milestone.issue_percent | |||||
| json.created_at milestone.created_on.strftime("%Y-%m-%d %H:%M") | |||||
| json.updated_on milestone.updated_on.strftime("%Y-%m-%d %H:%M") | |||||
| @@ -2,5 +2,7 @@ json.total_count @milestones.total_count | |||||
| json.milestones @milestones.each do |milestone| | json.milestones @milestones.each do |milestone| | ||||
| if params[:only_name] | if params[:only_name] | ||||
| json.partial! "simple_detail", locals: {milestone: milestone} | json.partial! "simple_detail", locals: {milestone: milestone} | ||||
| else | |||||
| json.partial! "detail", locals: {milestone: milestone} | |||||
| end | end | ||||
| end | end | ||||
| @@ -0,0 +1,11 @@ | |||||
| json.milestone do | |||||
| json.partial! "detail", locals: {milestone: @milestone} | |||||
| end | |||||
| json.total_issues_count @issues.total_count | |||||
| json.closed_issues_count @closed_issues_count | |||||
| json.opened_issues_count @opened_issues_count | |||||
| json.issues @issues.each do |issue| | |||||
| if issue.issue_classify == "Issue" | |||||
| json.partial! "api/v1/issues/simple_detail", locals: {issue: issue} | |||||
| end | |||||
| end | |||||