diff --git a/app/assets/javascripts/search.js b/app/assets/javascripts/search.js new file mode 100644 index 0000000..02f04be --- /dev/null +++ b/app/assets/javascripts/search.js @@ -0,0 +1,49 @@ +(function(){ + document.getElementById("search-form").reset(); + $("#serach-btn").on("click",function(){ + var el = $(this); + if(el.hasClass("opened")){ + $(".search-box input").stop().animate({"width":"0"},function(){ + $(".search-box").hide(); + el.removeClass("opened"); + }).val(""); + }else{ + $(".search-box").show(); + el.addClass("opened"); + $(".search-box input").stop().animate({"width":"200px"}).focus(); + } + return false; + }) + + var regex = new RegExp(/[a-z]+:/); + $("#smart-field-select").on("change",function(){ + var el = $(this), + old_value = $(".search-box input").val(), + matches = old_value.match(regex); + if(matches != null){ + old_value = old_value.replace(matches[0], el.val()); + if(el.val() == ""){ + old_value = old_value.trim(); + } + }else{ + old_value = el.val() + " " + old_value; + } + $(".search-box input").val(old_value).focus(); + }) + var interval = null; + $(".search-box input").on("keyup",function(){ + var el = $(this); + clearTimeout(interval); + interval = setTimeout(function(){ + var val = el.val(); + if(val == ""){ + $("#smart-field-select").find("option:eq(0)").prop("selected","selected"); + }else{ + var matches = val.match(regex); + if(matches != null){ + $("#smart-field-select").find('option[value="' + matches[0] + '"]').prop("selected","selected"); + } + } + },500); + }) +})() \ No newline at end of file diff --git a/app/assets/stylesheets/_ticket_variables.scss b/app/assets/stylesheets/_ticket_variables.scss new file mode 100644 index 0000000..3e922fa --- /dev/null +++ b/app/assets/stylesheets/_ticket_variables.scss @@ -0,0 +1,9 @@ +@charset "utf-8"; + +// colors +$blue: #326cc1; +$light-blue: #dce5e8; +$white: #fff; + +// units +$main-width: 1000px; \ No newline at end of file diff --git a/app/assets/stylesheets/ticket.scss b/app/assets/stylesheets/ticket.scss new file mode 100644 index 0000000..074b583 --- /dev/null +++ b/app/assets/stylesheets/ticket.scss @@ -0,0 +1,433 @@ + +@charset "utf-8"; +#main-wrap .wrap-inner { + padding-top: 20px !important; +} + +#new-ticket .no-space { + margin-bottom: 0px; + display: none; +} + +#connection-status { + text-align: center; +} + +#connection-status span.label { + font-size: 14px; + line-height: 18px; +} + +#ticket_loader { + text-align: center; +} + +#tickets_list tbody tr { + cursor: pointer; +} + +#tickets_list th.sort-field { + cursor: pointer; +} + +#ticket_footer_pagination { + text-align: center; + + @media screen and (max-width: 50rem) { + text-align: left; + } +} + +#ticket_footer_pagination .pagination { + margin: 0 0; +} + +.ticket-refresh-btn, +.ticket-create-btn { + margin-top: -14px; +} + +.label { + font-family: Arial, "Helvetica Neue", Helvetica, sans-serif; +} + +.ticket-modal { + width: 80%; + height: 700px; + max-width: 1000px; + bottom: 0; + left: 0; + right: 0; + margin: auto; +} + +.ticket-modal.modal.in { + top: 0; +} + +.ticket-modal .modal-body { + max-height: 560px; +} + +.ticket-modal .label-value { + width: auto; +} + +.search-wrap { + display: inline-block; +} + +#serach-btn { + font-size: 20px; + margin-right: 5px; + font-weight: bold; + text-decoration: none; +} + +.search-box { + display: none; +} + +.search-box input { + height: 14px; +} + +@media screen and (max-width: 800px) { + .ticket-modal .control-label { + float: none; + width: auto; + text-align: left; + padding: 0; + margin-bottom: 2px; + } + .ticket-modal .form-horizontal .controls { + margin-left: 0; + } + #new-ticket .no-space { + margin-bottom: 10px; + } +} + +// Ticket page +// helper classes +$primary: #2980b9; +$second: #489ad8; +$red: #d95f49; +$yellow: #F28A31; +$green: #69B556; +$dark-blue: #2e3e4f; +$gray: #888; +$light-gray: #edf0f1; +$white: #fff; +$black: #000; + +.t-list-unstyled { + list-style: none; + margin: 0; + padding: 0; +} + +.t-label { + border-radius: 0.125rem; + display: inline-block; + padding: 4px 0.5rem; + font-family: Arial, "Helvetica Neue", Helvetica, sans-serif; +} + +.t-label-primary { + color: $gray; + background-color: $white; +} + +.t-status { + text-transform: uppercase; + border-radius: 0.125rem; + font-size: 0.75rem; + display: inline-block; + padding: 4px 0.375rem; + font-family: Arial, "Helvetica Neue", Helvetica, sans-serif; +} + +.t-status-open { + color: $white; + background-color: $green; +} + +.t-status-close { + color: $white; + background-color: $gray; +} + +.t-status-in-progress { + color: $white; + background-color: $primary; +} + +.t-category { + text-transform: uppercase; + border-radius: 0.125rem; + display: inline-block; + padding: 4px 0.375rem; + font-family: Arial, "Helvetica Neue", Helvetica, sans-serif; +} + +.t-category-primary { + color: $white; + background-color: $yellow; +} + +.t-btn { + font-size: 0.8125rem; + color: $gray; + background-color: $white; +} + +.t-depth-1 { + margin-left: 1.5625rem; +} + +.ticket-breadcrumb { + width: 96%; + margin: auto; + max-width: 980px; + background: none; + font-family: Arial, "Helvetica Neue", Helvetica, sans-serif; + > li { + text-shadow: none; + } +} + +.ticket-wrap { + position: relative; + background-color: $white; + -webkit-border-bottom-right-radius: 0.25rem; + -webkit-border-bottom-left-radius: 0.25rem; + -moz-border-radius-bottomright: 0.25rem; + -moz-border-radius-bottomleft: 0.25rem; + border-bottom-right-radius: 0.25rem; + border-bottom-left-radius: 0.25rem; + -webkit-box-shadow: 0 2px 15px 0 rgba(0, 0, 0, .2); + box-shadow: 0 2px 15px 0 rgba(0, 0, 0, .2); + max-width: 1000px; + width: 96%; + margin: 0 auto; +} + +.ticket-heading-wrap { + background-color: $primary; + -webkit-border-top-left-radius: 4px; + -webkit-border-top-right-radius: 4px; + -moz-border-radius-topleft: 4px; + -moz-border-radius-topright: 4px; + border-top-left-radius: 4px; + border-top-right-radius: 4px; + &:hover { + .ticket-action { + top: 1.4rem; + opacity: 1; + } + } + .ticket-heading { + color: $white; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-weight: normal; + font-size: 1.5rem; + margin: 0; + padding: 12px 4rem 12px 1rem; + } +} + +.ticket-meta-wrap { + background-color: $second; + padding: 12px 1rem; + .ticket-meta { + color: #EDF0F1; + float: left; + font-size: 0.8125rem; + } + .ticket-state { + float: right; + } +} + +.ticket-action { + position: absolute; + right: 1.4rem; + top: -0.2rem; + opacity: 0; + transition: .3s all; + .dropdown-menu { + top: 120%; + left: auto; + right: 0; + padding: 15px 0; + border: none; + border-radius: 0.125rem; + min-width: 100px; + .t-btn { + i { + margin-right: 0.3125rem; + } + } + > li { + > a { + padding: 3px 0.75rem; + } + } + li { + > a { + &:hover { + background-color: $second; + background-image: none; + } + } + } + li { + > .ticket-delete { + &:hover { + background-color: $red; + } + } + > .ticket-close { + &:hover { + background-color: $yellow; + } + } + } + } +} + +.ticket-dropdown-icon { + color: rgba($white, .5); + font-size: 1.2rem; + text-align: center; + padding: 2px 0.3125rem; + border-radius: 0.25rem; + border: 3px solid rgba($white, .5); + transition: .2s all; + &:hover { + color: $white; + border-color: $white; + border-radius: 50%; + } +} + +.ticket-content { + padding: 10px 1.8rem 20px; + overflow: auto; +} + +.ticket-query { + margin: 15px 0 20px 0; + font-size: 0.9375rem; +} + +// response + +.ticket-response { + font-family: Arial, "Helvetica Neue", Helvetica, sans-serif; + border: 1px solid lighten($gray, 40%); +} + +.ticket-response-heading { + background-color: $second; + outline: 1px solid $second; + display: block; + padding: 6px 0.625rem; + color: $white; + font-size: 0.9375rem; + margin: 0 0 20px; +} + +.ticket-response-heading-icon { + margin-right: 0.5rem; +} + +.ticket-response-item { + margin: 35px auto; + width: 90%; +} + +.ticket-response-meta { + margin-bottom: 10px; + overflow: hidden; +} + +.ticket-response-author { + font-size: 1.25rem; + display: inline-block; + margin-right: 10px; + color: $black; +} + +.ticket-response-avatar { + width: 38px; + height: 38px; + border-radius: 50%; + margin-right: 0.3125rem; +} + +.ticket-response-created-date { + display: inline-block; + font-size: 0.8125rem; + font-style: italic; + color: $gray; + border-bottom: 1px dotted darken($light-gray, 5%); +} + +.ticket-response-content { + border: 1px solid lighten($gray, 40%); + padding: 15px 1.5rem; + border-radius: 0.125rem; + font-size: 0.9375rem; + line-height: 1.6; + overflow: auto; +} + +// editor +.ticket-editor { + padding: 10px 1.8rem 20px; +} + +// ticket table +.ticket-table { + td { + white-space: nowrap; + } +} + + + +// TODO joshua pleae change it +.ticket-category-select{ + border: medium none; + text-decoration: none; + color: $white; + border-radius: 0.125rem; + left: auto; + min-width: 100px; + padding: 15px 0; + right: 0; + top: 8.3%; +} + +.ticket-category-dropdown{ + color: $white; + text-decoration: none; + &:hover{ + color : $white; + text-decoration: none; + } + &:active{ + outline:none; + } + &:focus{ + outline:none; + } +} + +.popover[class*=tour-]{ + z-index: 1101; +} + +// till here \ No newline at end of file diff --git a/app/assets/stylesheets/ticket_index.scss b/app/assets/stylesheets/ticket_index.scss new file mode 100644 index 0000000..6b8ce1a --- /dev/null +++ b/app/assets/stylesheets/ticket_index.scss @@ -0,0 +1,38 @@ +@charset "utf-8"; +@import 'ticket_variables'; + + +.ticket-container { + max-width: $main-width; + width: 96%; + margin: auto; + background-color: $white; +} + + +.ticket-section-heading { + background-color: $blue; + color: $white; + padding: 10px 14px; +} +.ticket-section-container { + padding: 0 1rem; + margin-bottom: 20px; +} +.ticket-category-title { + background-color: #fff; +} + +.ticket-item { + padding: 8px 5px; + border-bottom: 1px solid $light-blue; +} + +.ticket-item:first-child { + border-top: 1px solid $light-blue; +} + +.ticket-section-view-all { + text-align: right; + margin: 20px 5px 40px; +} \ No newline at end of file diff --git a/app/assets/stylesheets/ticket_variables.scss b/app/assets/stylesheets/ticket_variables.scss new file mode 100644 index 0000000..1e70bd2 --- /dev/null +++ b/app/assets/stylesheets/ticket_variables.scss @@ -0,0 +1,9 @@ +@charset "utf-8"; + +// colors +$blue: #326cc1; +$light-blue: #dce5e8; + + +// units +$main-width: 1000px; \ No newline at end of file diff --git a/app/assets/stylesheets/tickets.css b/app/assets/stylesheets/tickets.css index 43dcc7a..093aa60 100644 --- a/app/assets/stylesheets/tickets.css +++ b/app/assets/stylesheets/tickets.css @@ -1,21 +1,28 @@ -/*css for tickets module*/ - hr{ - border-color: #761D1D -moz-use-text-color #ffffff; + border-color: #8E8E8E -moz-use-text-color #ffffff; margin-top: 5px; } .ticket{ - height: 50px; - margin-bottom: 15px; - box-shadow: 1px 1px 0 rgba(255, 255, 255, 0.4); - background-color: #EFEFEF; - border: 1px #007EBA solid; - border-radius: 5px; } .ticket .ticket-title{ font-size: 14px; margin-left: 15px; line-height: 45px; +} + +.category_ticket_wrap .search-wrap{ + /*float: left; + margin-top: -43px; + margin-left: 200px;*/ + display: inline; +} + +.category_ticket_wrap h3{ + width: auto; +} + +.urgent-container{ + /*background-color: #F7EEE2;*/ } \ No newline at end of file diff --git a/app/controllers/admin/tickets_api_controller.rb b/app/controllers/admin/tickets_api_controller.rb index 503084d..69513df 100644 --- a/app/controllers/admin/tickets_api_controller.rb +++ b/app/controllers/admin/tickets_api_controller.rb @@ -108,14 +108,15 @@ class Admin::TicketsApiController < ApplicationController response["ticket"]["creator_name"] = ticket.ticket_creater_name response["ticket"]["creator_id"] = ticket.ticket_creater_id response["ticket"]["queries"] = [] - ticket.ticket_queries.each do |qu| + ticket.ticket_queries.asc(:created_at).each do |qu| r = {"query" => qu.query, "responses" => []} - r["responses"] = qu.ticket_query_responses.collect do |qr| + r["responses"] = qu.ticket_query_responses.asc(:created_at).collect do |qr| user = User.find(qr.response_by) rescue nil { "response" => qr.response, "response_time" => qr.created_at, - "response_by" => (user.name if !user.nil?) + "response_by" => (user.name if !user.nil?), + "avatar" => ("http://" + request.host_with_port + user.member_profile.avatar.thumb.url if !user.member_profile.avatar.nil?) } end response["ticket"]["queries"] << r @@ -141,6 +142,7 @@ class Admin::TicketsApiController < ApplicationController t["ticket_type"] = ticket.category.title t["created_at"] = ticket.created_at t["subject"] = ticket.subject + t["reopened"] = ticket.reopened? t end end \ No newline at end of file diff --git a/app/controllers/admin/tickets_controller.rb b/app/controllers/admin/tickets_controller.rb index c0c33cd..ad7f8b6 100644 --- a/app/controllers/admin/tickets_controller.rb +++ b/app/controllers/admin/tickets_controller.rb @@ -1,40 +1,324 @@ class Admin::TicketsController < OrbitAdminController + before_action :set_smart_tags + def index mp = current_user.member_profile rescue nil @tickets = {} + @urgent_tickets = {} if !mp.nil? authorizations = Authorization.where(:role_id.in => mp.roles.collect{|mm| mm.id}) if authorizations.count == 0 @categories = ModuleApp.find_by_key("ticket").categories rescue [] @categories.each do |category| - if params[:status] == "closed" - @tickets[category] = Ticket.closed.limit(5).desc(:created_at) - else - @tickets[category] = Ticket.open.limit(5).desc(:created_at) - end + @tickets[category] = Ticket.open.not_urgent.limit(5).asc(:created_at) + @urgent_tickets[category] = Ticket.open.all_urgent.asc(:created_at) end else @categories = authorizations.collect{|authorization| authorization.category} @categories.each do |category| - if params[:status] == "closed" - temp = Ticket.where(:category_id => category.id).closed.limit(5).desc(:created_at) - @tickets[category] = temp if temp.count > 0 - else - temp = Ticket.where(:category_id => category.id).open.limit(5).desc(:created_at) - @tickets[category] = temp if temp.count > 0 - end + temp = Ticket.where(:category_id => category.id).open.not_urgent.limit(5).asc(:created_at) + @tickets[category] = temp if temp.count > 0 + temp = Ticket.where(:category_id => category.id).open.all_urgent.asc(:created_at) + @urgent_tickets[category] = temp if temp.count > 0 end end end end - def tickets_by_category - @table_fields = [:ticket_number, :site_name, :subject, :issued_time, :tags, :status, :taken_by] - @category = Category.find(params[:category_id]) rescue nil - if !@category.nil? - @tickets = Ticket.where(:category_id => @category.id, :status.in => ["open", "commenced"]).page(params[:page]).per(15).desc(:created_at) + def my_tickets + if params[:type] == "history" + @tickets = Ticket.where(:taken_by => current_user.id).closed.group_by(&:category) + else + @tickets = Ticket.where(:taken_by => current_user.id).commenced.desc(:urgent).group_by(&:category) + end + @categories = @tickets.keys + end + + def show + @ticket = Ticket.find(params[:id]) rescue nil + @categories = ModuleApp.find_by_key("ticket").categories + end + + def changecategory + ticket = Ticket.find(params[:ticket_id]) rescue nil + category = Category.find(params[:category_id]) rescue nil + if !category.nil? + ticket.category_id = category.id + ticket.save + end + redirect_to admin_ticket_path(ticket.id) + end + + def start + ticket = Ticket.find(params[:ticket_id]) rescue nil + ticket.status = "commenced" + ticket.taken_by = current_user.id + ticket.save + redirect_to admin_ticket_path(ticket.id) + end + + def close + ticket = Ticket.find(params[:ticket_id]) rescue nil + ticket.status = "closed" + ticket.urgent = false + ticket.save + redirect_to admin_ticket_path(ticket.id) + end + + def leave + ticket = Ticket.find(params[:ticket_id]) rescue nil + ticket.status = "open" + ticket.taken_by = nil + ticket.save + redirect_to admin_ticket_path(ticket.id) + end + + def toggleurgent + mark_urgent = params[:mark_urgent] + if mark_urgent + ticket = Ticket.find(params[:ticket_id]) rescue nil + if !ticket.nil? + if mark_urgent == "true" + if can_mark_urgent?(ticket) + ticket.urgent = true + ticket.save + response = {"success" => true, "can_make_urgent" => true} + else + response = {"success" => true, "can_make_urgent" => false} + end + else + ticket.urgent = false + ticket.save + response = {"success" => true, "can_make_urgent" => true} + end + else + response = {"success" => false} + end + end + render :json => response.to_json + end + + def search + statuses = ["open","commenced","closed"] + if params[:keywords].present? + keywords = params[:keywords] + type = (keywords.is_i? ? (keywords.length == 8 ? "number" : "text") : "text") + if type == "text" + regex = Regexp.new(/[a-z]+:/) + matches = keywords.scan(regex) + if !matches.blank? + smart_field = matches.first + if @smart_search_fields.include?(smart_field) + type = "smart" + keywords = keywords.sub(smart_field,"") + end + end + end + end + case type + when "number" + @tickets = Ticket.where(:status.in => statuses, :uid => keywords) + when "text" + @tickets = Ticket.where(:status.in => statuses) + @tickets = search_data(@tickets,[:subject, :uid, :status, :site_type, :ticket_creater_id, :ticket_creater_name]) + regex = Regexp.new(".*"+keywords+".*", "i") + sites = RegisteredSite.any_of({:title => regex},{:site_domain => regex}) + sites.each do |site| + @tickets = (@tickets | site.tickets.where(:status.in => statuses)) + end + when "smart" + @tickets = smart_search(statuses,nil,smart_field,keywords) + end + if !@tickets.nil? + @tickets = @tickets.group_by(&:category) + @categories = @tickets.keys + else + @tickets = {} + @categories = [] end end + + def submit_response + tq = TicketQuery.find(params[:ticket_query_id]) rescue nil + if !tq.nil? + response = TicketQueryResponse.new + response.response = params[:ticket_query_response] + response.response_by = current_user.id + response.save + tq.ticket_query_responses << response + render :partial => "response", :object => response + else + render :json => {"success" => true}.to_json + end + end + + def tickets_by_category + @table_fields = [:ticket_number, :site_name, :subject, :created_at, :tags, :status, :taken_by, :urgent] + statuses = params["type"] == "history" ? ["closed"] : ["open","commenced"] + @category = Category.find(params[:category_id]) rescue nil + if params[:keywords].present? + keywords = params[:keywords] + type = (keywords.is_i? ? (keywords.length == 8 ? "number" : "text") : "text") + if type == "text" + regex = Regexp.new(/[a-z]+:/) + matches = keywords.scan(regex) + if !matches.blank? + smart_field = matches.first + if @smart_search_fields.include?(smart_field) + type = "smart" + keywords = keywords.sub(smart_field,"") + end + end + end + end + if type.nil? + @tickets = Ticket.where(:category_id => @category.id, :status.in => statuses).order_by(sort).page(params[:page]).per(15) + else + case type + when "number" + @tickets = Ticket.where(:category_id => @category.id, :status.in => statuses, :uid => keywords).order_by(sort).page(params[:page]).per(15) + when "text" + @tickets = Ticket.where(:category_id => @category.id, :status.in => statuses).order_by(sort) + @tickets = search_data(@tickets,[:subject, :uid, :status, :site_type, :ticket_creater_id, :ticket_creater_name]) + regex = Regexp.new(".*"+keywords+".*", "i") + sites = RegisteredSite.any_of({:title => regex},{:site_domain => regex}) + sites.each do |site| + @tickets = (@tickets | site.tickets.where(:category_id => @category.id, :status.in => statuses)) + end + @tickets = Kaminari.paginate_array(@tickets).page(params[:page]).per(15) + when "smart" + @tickets = smart_search(statuses,@category,smart_field,keywords) + @tickets = @tickets.order_by(sort) rescue @tickets + @tickets = Kaminari.paginate_array(@tickets).page(params[:page]).per(15) + end + end if !@category.nil? + end + + private + + def can_mark_urgent?(ticket) + tickets = Ticket.where(:category_id => ticket.category_id, :urgent => true).count + return tickets < 5 + end + + def set_smart_tags + @smart_search_fields = ["sitename:","domain:","subject:","ticket:","status:","query:","type:","takenby:","time:"] + end + + def smart_search(statuses, category = nil, smart_field, keywords) + keywords = keywords.strip.nil? ? keywords : keywords.strip + regexes = keywords.split(/\s+(?=(?:[^"]*"[^"]*")*[^"]*$)/) + regex = Regexp.union(regexes.map{|word| Regexp.new(".*"+word+".*", "i")}) + tickets = [] + case smart_field + when "sitename:" + sites = RegisteredSite.where(:title => regex) + sites.each do |site| + if category.nil? + tickets = site.tickets.where(:status.in => statuses).limit(25) + else + tickets = site.tickets.where(:category_id => category.id, :status.in => statuses) + end + end + when "domain:" + sites = RegisteredSite.where(:site_domain => regex) + sites.each do |site| + if category.nil? + tickets = site.tickets.where(:status.in => statuses).limit(25) + else + tickets = site.tickets.where(:category_id => category.id, :status.in => statuses) + end + end + when "subject:" + if category.nil? + tickets = Ticket.where(:subject => regex, :status.in => statuses).limit(25) + else + tickets = Ticket.where(:subject => regex, :status.in => statuses, :category_id => category.id) + end + when "ticket:" + if category.nil? + tickets = Ticket.where(:uid => keywords) + else + tickets = Ticket.where(:uid => keywords, :category_id => category.id) + end + when "status:" + if category.nil? + tickets = Ticket.where(:status => keywords).limit(25) + else + tickets = Ticket.where(:status => keywords, :category_id => category.id) + end + when "type:" + category = Category.where(:"title.en" => regex).first rescue nil + if category.nil? + category = Category.where(:"title.zh_tw" => regex).first rescue nil + end + tickets = Ticket.where(:category_id => category.id, :status.in => statuses).limit(25) if !category.nil? + when "time:" + if keywords.include?("..") + times = keywords.split("..") + start_time = times.first + end_time = times.last + start_time = start_time + ".01" if start_time.length <= 7 + end_time = end_time + ".#{Time.days_in_month(end_time.split(".").last.to_i, end_time.split(".").first.to_i)}" if end_time.length <= 7 + start_date = DateTime.parse(start_time) - 1 rescue nil + end_date = DateTime.parse(end_time) + 1 rescue nil + else + if keywords.length <= 7 + start_time = keywords + ".01" + end_time = keywords + ".#{Time.days_in_month(keywords.split(".").last.to_i, keywords.split(".").first.to_i)}" + start_date = DateTime.parse(start_time) - 1 rescue nil + end_date = DateTime.parse(end_time) + 1 rescue nil + else + start_time = keywords + start_date = DateTime.parse(start_time) rescue nil + end_date = DateTime.parse(start_time) + 1 rescue nil + end + end + return tickets if start_date.nil? || end_date.nil? + if category.nil? + tickets = Ticket.where(:created_at => (start_date..end_date), :status.in => statuses).limit(25) + else + tickets = Ticket.where(:created_at => (start_date..end_date), :status.in => statuses, :category_id => category.id) + end + when "takenby:" + profiles = MemberProfile.any_of({:"first_name.en" => regex},{:"first_name.zh_tw" => regex},{:"last_name.en" => regex},{:"last_name.zh_tw" => regex}) + profiles.each do |profile| + user_id = profile.user.id + if category.nil? + tickets = (tickets | Ticket.where(:taken_by => user_id, :status.in => statuses)) + else + tickets = (tickets | Ticket.where(:taken_by => user_id, :category_id => category.id, :status.in => statuses)) + end + end + when "query:" + queries = TicketQuery.where(:query => regex).limit(25) + queries.each do |query| + if category.nil? + tickets << query.ticket if statuses.include?(query.ticket.status) && !tickets.include?(query.ticket) + else + tickets << query.ticket if statuses.include?(query.ticket.status) && query.ticket.category_id == category.id && !tickets.include?(query.ticket) + end + end + if params[:sort].present? + s = Sanitize.clean(params[:sort]).to_sym + if params[:order] == "desc" + tickets = tickets.sort{|a,b| b[s] <=> a[s]} + elsif params[:order] == "asc" + tickets = tickets.sort{|a,b| a[s] <=> b[s]} + end + end + end + tickets + end -end \ No newline at end of file +end + + + + + + + + + diff --git a/app/models/ticket.rb b/app/models/ticket.rb index 22ca4d1..2609e18 100644 --- a/app/models/ticket.rb +++ b/app/models/ticket.rb @@ -9,6 +9,7 @@ class Ticket field :ticket_creater_id field :ticket_creater_name field :subject + field :urgent, type: Boolean, default: false field :reopened_count, type: Integer, :default => 0 field :status, :default => "open" field :taken_by, type: BSON::ObjectId @@ -16,6 +17,8 @@ class Ticket scope :open, ->{ where(status: "open") } scope :closed, ->{ where(status: "closed") } scope :commenced, ->{ where(status: "commenced") } + scope :not_urgent, ->{ where(:urgent.in => [false,nil]) } + scope :all_urgent, ->{ where(urgent: true) } belongs_to :registered_site @@ -27,5 +30,19 @@ class Ticket self.reopened_count < 2 end + def is_urgent? + self.urgent + end + def reopened? + self.reopened_count > 0 + end + + def registered_site_title + self.registered_site.title + end + + def registered_site_domain + self.registered_site.site_domain + end end \ No newline at end of file diff --git a/app/views/admin/tickets/_query.html.erb b/app/views/admin/tickets/_query.html.erb new file mode 100644 index 0000000..12fe8a6 --- /dev/null +++ b/app/views/admin/tickets/_query.html.erb @@ -0,0 +1,25 @@ +
+ <%= query.query.html_safe %> +
+
+

+ + Response +

+
> + <%= render :partial => "response", :collection => query.ticket_query_responses %> +
+ <% if params[:reopen] != "true" && @ticket.ticket_queries.count == (query_counter + 1) %> +
+
+ + +
+ +
+ + <% end %> +
\ No newline at end of file diff --git a/app/views/admin/tickets/_response.html.erb b/app/views/admin/tickets/_response.html.erb new file mode 100644 index 0000000..d802258 --- /dev/null +++ b/app/views/admin/tickets/_response.html.erb @@ -0,0 +1,15 @@ +
+
+
+ <% user = User.find(response.response_by) rescue nil %> + + <%= user.name if !user.nil? %> +
+
+ <% dt = DateTime.parse(response.created_at.to_s) %> <%= dt.strftime("%d %B %Y - %H:%M") %> +
+
+
+ <%= response.response.html_safe %> +
+
\ No newline at end of file diff --git a/app/views/admin/tickets/_search_form.html.erb b/app/views/admin/tickets/_search_form.html.erb new file mode 100644 index 0000000..d492a4e --- /dev/null +++ b/app/views/admin/tickets/_search_form.html.erb @@ -0,0 +1,18 @@ +
+ + <% if params[:keywords].present? %> + + Searched for <%= params[:keywords] %> + <% end %> + +
\ No newline at end of file diff --git a/app/views/admin/tickets/_ticket.html.erb b/app/views/admin/tickets/_ticket.html.erb index 6678039..792ed35 100644 --- a/app/views/admin/tickets/_ticket.html.erb +++ b/app/views/admin/tickets/_ticket.html.erb @@ -1,3 +1,29 @@ -
- <%= ticket.subject %> -
\ No newline at end of file +<% return if ticket_counter >= 5 %> +<% case ticket.status + when "open" + badge_class = "t-status-open" + when "closed" + badge_class = "t-status-close" + when "commenced" + badge_class = "t-status-in-progress" + end +%> +
+ #<%= ticket.uid %> - <%= ticket.subject %> (<%= ticket.registered_site.title %>) +
+ <% if ticket.is_urgent? %> + Urgent + <% end %> + + + <%= ticket.status %> + + <% if !ticket.taken_by.nil? %> + + + <% user = User.find(ticket.taken_by) %> + <%= user.name if !user.nil? %> + + <% end %> +
+
diff --git a/app/views/admin/tickets/_ticket_by_c.html.erb b/app/views/admin/tickets/_ticket_by_c.html.erb index 1f03ced..8991224 100644 --- a/app/views/admin/tickets/_ticket_by_c.html.erb +++ b/app/views/admin/tickets/_ticket_by_c.html.erb @@ -3,7 +3,7 @@ badge_class = "badge-info" when "closed" badge_class = "badge-inverse" - when "processing" + when "commenced" badge_class = "badge-success" end %> @@ -24,6 +24,23 @@ <%= ticket_by_c.status %> + <% if (ticket_by_c.status == "open" || ticket_by_c.status == "commenced") && ticket_by_c.reopened? %> + Reopened + <% end %> + + + <% if !ticket_by_c.taken_by.nil? + user = User.find(ticket_by_c.taken_by) rescue nil%> + <%= user.name if !user.nil? %> + <% else %> +   + <% end %> + + + <% if ticket_by_c.is_urgent? %> +   + <% else %> +   + <% end %> -   diff --git a/app/views/admin/tickets/index.html.erb b/app/views/admin/tickets/index.html.erb index 2c5282e..47b1f42 100644 --- a/app/views/admin/tickets/index.html.erb +++ b/app/views/admin/tickets/index.html.erb @@ -1,13 +1,36 @@ <% content_for :page_specific_css do %> + <%= stylesheet_link_tag "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" %> + <%= stylesheet_link_tag "ticket_index" %> <%= stylesheet_link_tag "tickets" %> + <%= stylesheet_link_tag "ticket" %> <% end %> -
+<%= render :partial => "search_form" %> +
+
+

Urgent Tickets

+ <% @categories.each do |category| %> + <% if !@urgent_tickets[category].nil? %> +
+

<%= category.title %>

+ <%= render :partial => "ticket", :collection => @urgent_tickets[category] %> +
+ <% end %> + <% end %> +
+

Normal Tickets

<% @categories.each do |category| %> -
-

<%= category.title %>

-
- <%= render :partial => "ticket", :collection => @tickets[category] %> -
- +
+

<%= category.title %>

+ <%= render :partial => "ticket", :collection => @tickets[category] %> + +
<% end %> -
\ No newline at end of file +
+ + + + + + diff --git a/app/views/admin/tickets/my_tickets.html.erb b/app/views/admin/tickets/my_tickets.html.erb new file mode 100644 index 0000000..8a686e4 --- /dev/null +++ b/app/views/admin/tickets/my_tickets.html.erb @@ -0,0 +1,31 @@ +<% content_for :page_specific_css do %> + <%= stylesheet_link_tag "tickets" %> + <%= stylesheet_link_tag "ticket" %> +<% end %> +<%= render :partial => "search_form" %> +
+<% if params[:type] == "history" %> + View my current tickets +<% else %> + View my past tickets +<% end %> +
+
+<% @categories.each do |category| %> +
+

<%= category.title %>

+
+ <%= render :partial => "ticket", :collection => @tickets[category] %> +
+
View all tickets from <%= category.title %>
+
+<% end %> +
+ + + + + + + + diff --git a/app/views/admin/tickets/search.html.erb b/app/views/admin/tickets/search.html.erb new file mode 100644 index 0000000..e0604cf --- /dev/null +++ b/app/views/admin/tickets/search.html.erb @@ -0,0 +1,15 @@ +<% content_for :page_specific_css do %> + <%= stylesheet_link_tag "tickets" %> + <%= stylesheet_link_tag "ticket" %> +<% end %> +<%= render :partial => "search_form" %> +
+<% @categories.each do |category| %> +
+

<%= category.title %>

+ <%= render :partial => "ticket", :collection => @tickets[category] %> +
+
">View all tickets from <%= category.title %>
+<% end %> +
+ diff --git a/app/views/admin/tickets/show.html.erb b/app/views/admin/tickets/show.html.erb index 5f365d7..aab7860 100644 --- a/app/views/admin/tickets/show.html.erb +++ b/app/views/admin/tickets/show.html.erb @@ -1 +1,223 @@ -this is show \ No newline at end of file +<% content_for :page_specific_css do %> + <%= stylesheet_link_tag "https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css" %> + <%= stylesheet_link_tag "ticket" %> +<% end %> +<% content_for :page_specific_javascript do %> + <%= javascript_include_tag "lib/jquery.form.js" %> + <%= javascript_include_tag "validator" %> +<% end %> +<% if !@ticket .nil? %> +<% case @ticket.status + when "open" + badge_class = "t-status-open" + when "closed" + badge_class = "t-status-close" + when "commenced" + badge_class = "t-status-in-progress" + end +%> +
+
+
> +

#<%= @ticket.uid %> - <%= @ticket.subject[0..50] %> + <% if !@ticket.taken_by.nil? %> + <% user = User.find(@ticket.taken_by) %> + + <% end %> +

+
+
+ + + + +
+
+
+
+
+ + + <%= !@ticket.ticket_creater_name.nil? ? @ticket.ticket_creater_name : @ticket.ticket_creater_id %> + + + + <% dt = DateTime.parse(@ticket.created_at.to_s) %> <%= dt.strftime("%d %B %Y - %H:%M") %> + +
+
+ <% if @ticket.status != "closed" %> + " id="toggle-urgent">Urgent + <% end %> + + + <%= @ticket.status %> + + + + + <%= @ticket.category.title %> + + + + +
+
+
+ +
+ <%= render :partial => "query", :collection => @ticket.ticket_queries %> +
+ <% if params[:reopen] == "true"%> + <% if @ticket.status == "closed" %> +
+
+ + +
+ + +
+ + <% else %> +

Ticket is already opened.

+ <% end %> + <% end %> +
+<% else %> +
+ Error in fetching ticket. +
+<% end %> + + + + diff --git a/app/views/admin/tickets/tickets_by_category.html.erb b/app/views/admin/tickets/tickets_by_category.html.erb index 90944b7..2917936 100644 --- a/app/views/admin/tickets/tickets_by_category.html.erb +++ b/app/views/admin/tickets/tickets_by_category.html.erb @@ -1,5 +1,47 @@ -
-

<%= @category.title %>

+<% content_for :page_specific_css do %> + <%= stylesheet_link_tag "tickets" %> +<% end %> +
+<% if !@category.nil? %> +
+

+ <%= @category.title %><%= " - history" if params[:type] == "history" %> +
+ + <% if params[:keywords].present? %> + " style="font-size:20px;"> + Searched for <%= params[:keywords] %> + <% end %> + +
+

+ <% h = request.original_fullpath.split("?")[1] %> + <% if params[:type] == "history" %> + <% h = h.gsub("type=history","").chomp("&") %> + ">View current + <% else %> + <% h = h.nil? ? "type=history" : "#{h}&type=history" %> + View history + <% end %> +
+<% else %> +
+

Category Not found!

+
+<% end %> @@ -9,17 +51,19 @@ - <% if !@tickets.nil? %> + <% if !@tickets.nil? && @tickets.count > 0 %> <%= render :partial => "ticket_by_c", :collection => @tickets %> <% else %> - + <% end %>
No tickets for <%= @category.title rescue "" %>
No tickets.
-<%= - content_tag :div, class: "bottomnav clearfix" do - content_tag :div, paginate(@tickets), class: "pagination pagination-centered" - end -%> + <% if !@tickets.nil? && @tickets.count > 0 %> + <%= + content_tag :div, class: "bottomnav clearfix" do + content_tag :div, paginate(@tickets), class: "pagination pagination-centered" + end + %> +<% end %>
- + diff --git a/config/locales/en.yml b/config/locales/en.yml index cf3fe80..f7e1679 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1,4 +1,5 @@ en: tickets: tickets: Tickets + my_tickets: My Tickets all: All diff --git a/config/locales/zh_tw.yml b/config/locales/zh_tw.yml index 796be65..15d8640 100644 --- a/config/locales/zh_tw.yml +++ b/config/locales/zh_tw.yml @@ -1,4 +1,5 @@ zh_tw: tickets: tickets: Tickets + my_tickets: My Tickets all: All diff --git a/config/routes.rb b/config/routes.rb index de8c5e0..2a9a62f 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -11,8 +11,17 @@ Rails.application.routes.draw do get "/xhr/ticket/types", to: 'admin/tickets_api#tickettypes' delete "/xhr/ticket/:ticket_id", to: 'admin/tickets_api#destroy' namespace :admin do + get "tickets/search" => 'tickets#search' + post "ticket/submit_response" => 'tickets#submit_response' get "tickets/category/:category_id" => 'tickets#tickets_by_category' - resources :tickets + get "tickets/my_tickets" => 'tickets#my_tickets' + resources :tickets do + get "start" + get "leave" + get "changecategory" + get "close" + post "toggleurgent" + end end end diff --git a/lib/tickets/engine.rb b/lib/tickets/engine.rb index 2fa040a..3a72a14 100644 --- a/lib/tickets/engine.rb +++ b/lib/tickets/engine.rb @@ -20,6 +20,12 @@ module Tickets :active_for_action=>{'admin/tickets'=>"index"}, :available_for => 'users' + context_link 'tickets.my_tickets', + :link_path=>"admin_tickets_my_tickets_path" , + :priority=>2, + :active_for_action=>{'admin/tickets'=>"my_tickets"}, + :available_for => 'users' + context_link 'categories', :link_path=>"admin_module_app_categories_path" , :link_arg=>"{:module_app_id=>ModuleApp.find_by(:key=>'ticket').id}",