| @@ -1,32 +1,67 @@ | |||
| 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 | |||
| 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 | |||
| @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 | |||
| @milestones = @milestones.ransack(name_or_description_cont: params[:keyword]).result if params[:keyword].present? | |||
| @milestones = kaminary_select_paginate(@milestones) | |||
| 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 | |||
| 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 | |||
| def update | |||
| @milestone.attributes = milestone_params | |||
| if @milestone.save! | |||
| render_ok | |||
| else | |||
| render_error(@milestone.errors.full_messages.join(",")) | |||
| end | |||
| end | |||
| def destroy | |||
| if @milestone.destroy! | |||
| render_ok | |||
| else | |||
| render_error("删除里程碑失败!") | |||
| end | |||
| end | |||
| 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 | |||
| @@ -28,6 +28,9 @@ class Version < ApplicationRecord | |||
| has_many :issues, class_name: "Issue", foreign_key: "fixed_version_id" | |||
| 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 :closed, ->{where(status: 'closed')} | |||
| scope :opening, ->{where(status: 'open')} | |||
| @@ -43,6 +46,11 @@ class Version < ApplicationRecord | |||
| after_create :send_create_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 | |||
| User.select(:login, :lastname,:firstname, :nickname)&.find_by_id(self.user_id) | |||
| end | |||
| @@ -53,6 +61,6 @@ class Version < ApplicationRecord | |||
| end | |||
| 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 | |||
| @@ -20,7 +20,9 @@ class Api::V1::Issues::BatchUpdateService < ApplicationService | |||
| raise Error, errors.full_messages.join(", ") unless valid? | |||
| ActiveRecord::Base.transaction do | |||
| @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 | |||
| 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| | |||
| if params[:only_name] | |||
| json.partial! "simple_detail", locals: {milestone: milestone} | |||
| else | |||
| json.partial! "detail", locals: {milestone: milestone} | |||
| 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 | |||