tickets updates
This commit is contained in:
parent
10014335cb
commit
3434cd9ae8
|
@ -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);
|
||||
})
|
||||
})()
|
|
@ -0,0 +1,9 @@
|
|||
@charset "utf-8";
|
||||
|
||||
// colors
|
||||
$blue: #326cc1;
|
||||
$light-blue: #dce5e8;
|
||||
$white: #fff;
|
||||
|
||||
// units
|
||||
$main-width: 1000px;
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
@charset "utf-8";
|
||||
|
||||
// colors
|
||||
$blue: #326cc1;
|
||||
$light-blue: #dce5e8;
|
||||
|
||||
|
||||
// units
|
||||
$main-width: 1000px;
|
|
@ -1,17 +1,9 @@
|
|||
/*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{
|
||||
|
@ -19,3 +11,18 @@ hr{
|
|||
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;*/
|
||||
}
|
|
@ -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
|
|
@ -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)
|
||||
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 my_tickets
|
||||
if params[:type] == "history"
|
||||
@tickets = Ticket.where(:taken_by => current_user.id).closed.group_by(&:category)
|
||||
else
|
||||
temp = Ticket.where(:category_id => category.id).open.limit(5).desc(:created_at)
|
||||
@tickets[category] = temp if temp.count > 0
|
||||
@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, :issued_time, :tags, :status, :taken_by]
|
||||
@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 !@category.nil?
|
||||
@tickets = Ticket.where(:category_id => @category.id, :status.in => ["open", "commenced"]).page(params[:page]).per(15).desc(:created_at)
|
||||
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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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
|
|
@ -0,0 +1,25 @@
|
|||
<div class="query ticket-query">
|
||||
<%= query.query.html_safe %>
|
||||
</div>
|
||||
<div class="ticket-response t-depth-1">
|
||||
<h4 class="ticket-response-heading">
|
||||
<i class="ticket-response-heading-icon fa fa-commenting"></i>
|
||||
Response
|
||||
</h4>
|
||||
<div <%= @ticket.ticket_queries.count == (query_counter + 1) ? "id=response-container" : "" %>>
|
||||
<%= render :partial => "response", :collection => query.ticket_query_responses %>
|
||||
</div>
|
||||
<% if params[:reopen] != "true" && @ticket.ticket_queries.count == (query_counter + 1) %>
|
||||
<div id="form_container" class="ticket-editor">
|
||||
<form method="post" action="/admin/ticket/submit_response" id="reopen-form" for="query-response">
|
||||
<textarea class="ckeditor" name="ticket_query_response" data-fv-validation="required;" data-fv-messages="Cannot be empty;"></textarea>
|
||||
<input type="hidden" name="ticket_query_id" value="<%= query.id.to_s %>" />
|
||||
</form>
|
||||
<input type="submit" id="reopen-form-submit" class="btn btn-primary" value="Submit" />
|
||||
</div>
|
||||
<div id="ticket_loader" style="display:none;">
|
||||
<%= image_tag("preloader.gif", size: "50") %>
|
||||
<div>Posting your response.</div>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
|
@ -0,0 +1,15 @@
|
|||
<div class="ticket-response-item">
|
||||
<div class="ticket-response-meta">
|
||||
<div class="ticket-response-author">
|
||||
<% user = User.find(response.response_by) rescue nil %>
|
||||
<img class="ticket-response-avatar" src="<%= user.member_profile.avatar.thumb.url if !user.member_profile.avatar.nil? %>" />
|
||||
<span class="ticket-response-name"><%= user.name if !user.nil? %></span>
|
||||
</div>
|
||||
<div class="ticket-response-created-date">
|
||||
<% dt = DateTime.parse(response.created_at.to_s) %> <%= dt.strftime("%d %B %Y - %H:%M") %>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ticket-response-content">
|
||||
<%= response.response.html_safe %>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,18 @@
|
|||
<div class="search-wrap">
|
||||
<a href="#" id="serach-btn" style="font-size:20px;"><i class="icons-search"></i></a>
|
||||
<% if params[:keywords].present? %>
|
||||
<a href="/admin/tickets" style="font-size:20px;"><i class="icons-cycle"></i></a>
|
||||
<span>Searched for <b><i><%= params[:keywords] %></i></b></span>
|
||||
<% end %>
|
||||
<span class="search-box" style="display:none;">
|
||||
<form action="/admin/tickets/search" method="get" id="search-form">
|
||||
<select id="smart-field-select" style="width:100px;">
|
||||
<option value="">general</option>
|
||||
<% @smart_search_fields.each do |ssf| %>
|
||||
<option value="<%= ssf %>"><%= ssf %></option>
|
||||
<% end %>
|
||||
</select>
|
||||
<input type="text" placeholder="Search" style="width:0;" name="keywords" />
|
||||
</form>
|
||||
</span>
|
||||
</div>
|
|
@ -1,3 +1,29 @@
|
|||
<div class="ticket" id="ticket_<%= ticket.id.to_s %>" data-id="<%= ticket.id.to_s %>">
|
||||
<span class="ticket-title"><%= ticket.subject %></span>
|
||||
<% 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
|
||||
%>
|
||||
<div class="ticket ticket-item" id="ticket_<%= ticket.id.to_s %>" data-id="<%= ticket.id.to_s %>">
|
||||
#<%= ticket.uid %> - <a href="<%= admin_ticket_path(ticket.id) %>"><span class="ticket-title"><%= ticket.subject %></span> </a><a href="http://<%= ticket.registered_site.site_domain %>" target="_blank">(<%= ticket.registered_site.title %>)</a>
|
||||
<div class="pull-right">
|
||||
<% if ticket.is_urgent? %>
|
||||
<span class="label label-danger">Urgent</span>
|
||||
<% end %>
|
||||
<span class="label label-info <%= badge_class %>">
|
||||
<i class="fa fa-eye"></i>
|
||||
<%= ticket.status %>
|
||||
</span>
|
||||
<% if !ticket.taken_by.nil? %>
|
||||
<span class="ticket-author t-label t-label-primary">
|
||||
<i class="icon-user"></i>
|
||||
<% user = User.find(ticket.taken_by) %>
|
||||
<%= user.name if !user.nil? %>
|
||||
</span>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
|
@ -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 @@
|
|||
</td>
|
||||
<td>
|
||||
<span class="label <%= badge_class %>"><%= ticket_by_c.status %></span>
|
||||
<% if (ticket_by_c.status == "open" || ticket_by_c.status == "commenced") && ticket_by_c.reopened? %>
|
||||
<span class="label badge-success">Reopened</span>
|
||||
<% end %>
|
||||
</td>
|
||||
<td class="span2">
|
||||
<% if !ticket_by_c.taken_by.nil?
|
||||
user = User.find(ticket_by_c.taken_by) rescue nil%>
|
||||
<%= user.name if !user.nil? %>
|
||||
<% else %>
|
||||
|
||||
<% end %>
|
||||
</td>
|
||||
<td class="span1">
|
||||
<% if ticket_by_c.is_urgent? %>
|
||||
<span class="badge label badge-important"> </span>
|
||||
<% else %>
|
||||
<span class="badge label badge-success"> </span>
|
||||
<% end %>
|
||||
</td>
|
||||
<td class="span2"> </td>
|
||||
</tr>
|
||||
|
|
|
@ -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 %>
|
||||
<div>
|
||||
<%= render :partial => "search_form" %>
|
||||
<div class="ticket-container">
|
||||
<div class="ticket-section-container">
|
||||
<h3 class="ticket-section-heading">Urgent Tickets</h3>
|
||||
<% @categories.each do |category| %>
|
||||
<div>
|
||||
<h3><%= category.title %></h3>
|
||||
<hr>
|
||||
<%= render :partial => "ticket", :collection => @tickets[category] %>
|
||||
<% if !@urgent_tickets[category].nil? %>
|
||||
<div class="ticket-section-container">
|
||||
<h4 class="ticket-category-title"><%= category.title %></h4>
|
||||
<%= render :partial => "ticket", :collection => @urgent_tickets[category] %>
|
||||
</div>
|
||||
<div class="pull-right"><a href="/admin/tickets/category/<%= category.id.to_s %>">View all tickets from <%= category.title %></a></div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
<h3 class="ticket-section-heading">Normal Tickets</h3>
|
||||
<% @categories.each do |category| %>
|
||||
<div class="ticket-section-container">
|
||||
<h4 class="ticket-category-title"><%= category.title %></h4>
|
||||
<%= render :partial => "ticket", :collection => @tickets[category] %>
|
||||
<div class="ticket-section-view-all">
|
||||
<a class="btn btn-primary" href="/admin/tickets/category/<%= category.id.to_s %>">View all tickets from <%= category.title %></a>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
<script type="text/javascript" src="/assets/search.js"></script>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
<% content_for :page_specific_css do %>
|
||||
<%= stylesheet_link_tag "tickets" %>
|
||||
<%= stylesheet_link_tag "ticket" %>
|
||||
<% end %>
|
||||
<%= render :partial => "search_form" %>
|
||||
<div class="pull-right">
|
||||
<% if params[:type] == "history" %>
|
||||
<a href="/admin/tickets/my_tickets">View my current tickets</a>
|
||||
<% else %>
|
||||
<a href="/admin/tickets/my_tickets?type=history">View my past tickets</a>
|
||||
<% end %>
|
||||
</div>
|
||||
<div>
|
||||
<% @categories.each do |category| %>
|
||||
<div>
|
||||
<h3><%= category.title %></h3>
|
||||
<hr>
|
||||
<%= render :partial => "ticket", :collection => @tickets[category] %>
|
||||
</div>
|
||||
<div class="pull-right"><a href="/admin/tickets/category/<%= category.id.to_s %>/?keywords=takenby: <%= current_user.name %>">View all tickets from <%= category.title %></a></div>
|
||||
<br>
|
||||
<% end %>
|
||||
</div>
|
||||
<script type="text/javascript" src="/assets/search.js"></script>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<% content_for :page_specific_css do %>
|
||||
<%= stylesheet_link_tag "tickets" %>
|
||||
<%= stylesheet_link_tag "ticket" %>
|
||||
<% end %>
|
||||
<%= render :partial => "search_form" %>
|
||||
<div>
|
||||
<% @categories.each do |category| %>
|
||||
<div>
|
||||
<h3><%= category.title %></h3>
|
||||
<%= render :partial => "ticket", :collection => @tickets[category] %>
|
||||
</div>
|
||||
<div class="pull-right"><a href="/admin/tickets/category/<%= category.id.to_s %>/?<%= request.original_fullpath.split("?")[1] %>">View all tickets from <%= category.title %></a></div>
|
||||
<% end %>
|
||||
</div>
|
||||
<script type="text/javascript" src="/assets/search.js"></script>
|
|
@ -1 +1,223 @@
|
|||
this is show
|
||||
<% 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
|
||||
%>
|
||||
<div class="ticket-wrap">
|
||||
<div class="ticket-header">
|
||||
<div id="ticket-urgent-marker" class="ticket-heading-wrap" <%= "style=background-color:#C61C2D;" if @ticket.is_urgent? %>>
|
||||
<h3 class="ticket-heading">#<%= @ticket.uid %> - <%= @ticket.subject[0..50] %>
|
||||
<% if !@ticket.taken_by.nil? %>
|
||||
<% user = User.find(@ticket.taken_by) %>
|
||||
<img src="<%= user.member_profile.avatar.thumb.url if !user.member_profile.avatar.nil? %>" style="border-radius: 50%;height: 30px;margin-right: 0.3125rem;width: 30px;" />
|
||||
<% end %>
|
||||
</h3>
|
||||
<div class="ticket-action">
|
||||
<div class="ticket-dropdown">
|
||||
<a class="ticket-dropdown-toggle" data-toggle="dropdown" href="#">
|
||||
<i class="ticket-dropdown-icon fa fa-angle-down"></i>
|
||||
</a>
|
||||
<ul class="t-list-unstyled dropdown-menu" role="menu">
|
||||
<% if @ticket.status == "open" %>
|
||||
<li>
|
||||
<a class="ticket-start t-btn" href="/admin/tickets/<%= @ticket.id.to_s %>/start" data-ticket-id="<%= @ticket.id.to_s %>">
|
||||
<i class="fa fa-times-circle"></i>
|
||||
Start
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="ticket-close t-btn" href="/admin/tickets/<%= @ticket.id.to_s %>/close" data-ticket-id="<%= @ticket.id.to_s %>">
|
||||
<i class="fa fa-eye-slash"></i>
|
||||
Close
|
||||
</a>
|
||||
</li>
|
||||
<% elsif @ticket.status == "commenced" %>
|
||||
<li>
|
||||
<a class="ticket-start t-btn" data-confirm="Are you sure?" href="/admin/tickets/<%= @ticket.id.to_s %>/leave" data-ticket-id="<%= @ticket.id.to_s %>">
|
||||
<i class="fa fa-times-circle"></i>
|
||||
Leave
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="ticket-close t-btn" href="/admin/tickets/<%= @ticket.id.to_s %>/close" data-ticket-id="<%= @ticket.id.to_s %>">
|
||||
<i class="fa fa-eye-slash"></i>
|
||||
Close
|
||||
</a>
|
||||
</li>
|
||||
<% elsif @ticket.status == "closed" %>
|
||||
<% if @ticket.can_be_reopened? %>
|
||||
<li>
|
||||
<% if params[:reopen] == "true" %>
|
||||
<a href="#" class="reopen-back-btn t-btn" >Cancel</a>
|
||||
<% else %>
|
||||
<a href="/admin/tickets/<%= @ticket.id.to_s %>?reopen=true" class="t-btn">Reopen</a>
|
||||
<% end %>
|
||||
</li>
|
||||
<% else %>
|
||||
<li>
|
||||
This ticket cannot be reopened. Please create a new ticket.
|
||||
</li>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ticket-meta-wrap clearfix">
|
||||
<div class="ticket-meta">
|
||||
<span class="ticket-author t-label t-label-primary">
|
||||
<i class="icon-user"></i>
|
||||
<%= !@ticket.ticket_creater_name.nil? ? @ticket.ticket_creater_name : @ticket.ticket_creater_id %>
|
||||
</span>
|
||||
<span class="ticket-created-date t-label t-label-primary">
|
||||
<i class="icon-time"></i>
|
||||
<% dt = DateTime.parse(@ticket.created_at.to_s) %> <%= dt.strftime("%d %B %Y - %H:%M") %>
|
||||
</span>
|
||||
</div>
|
||||
<div class="ticket-state">
|
||||
<% if @ticket.status != "closed" %>
|
||||
<a href="/admin/tickets/<%= @ticket.id.to_s %>/toggleurgent" class="btn btn-danger <%= "active" if @ticket.is_urgent? %>" id="toggle-urgent">Urgent</a>
|
||||
<% end %>
|
||||
<span class="ticket-status t-status <%= badge_class %>">
|
||||
<i class="fa fa-eye"></i>
|
||||
<%= @ticket.status %>
|
||||
</span>
|
||||
<span class="ticket-category t-category t-category-primary">
|
||||
<a class="ticket-category-dropdown" data-toggle="dropdown" href="#">
|
||||
<i class="fa fa-th-list"></i>
|
||||
<%= @ticket.category.title %>
|
||||
<i class="fa fa-angle-down"></i>
|
||||
</a>
|
||||
<ul class="ticket-category-select dropdown-menu" role="menu">
|
||||
<% @categories.each do |category| %>
|
||||
<li>
|
||||
<a class="ticket-start t-btn ticket-category-select-option" href="#" data-category-id="<%= category.id.to_s %>">
|
||||
<%= category.title %>
|
||||
</a>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="query_box" class="ticket-content">
|
||||
<%= render :partial => "query", :collection => @ticket.ticket_queries %>
|
||||
</div>
|
||||
<% if params[:reopen] == "true"%>
|
||||
<% if @ticket.status == "closed" %>
|
||||
<div id="form_container" class="ticket-editor">
|
||||
<form method="post" action="/admin/ticket/reopen" id="reopen-form" for="query">
|
||||
<textarea class="ckeditor" name="ticket_query" data-fv-validation="required;" data-fv-messages="Cannot be empty;"></textarea>
|
||||
<input type="hidden" name="ticket_id" value="<%= @ticket.uid %>" />
|
||||
</form>
|
||||
<input type="submit" id="reopen-form-submit" class="btn btn-primary" value="Reopen" />
|
||||
<input type="button" class="btn reopen-back-btn" value="Cancel" />
|
||||
</div>
|
||||
<div id="ticket_loader" style="display:none;">
|
||||
<%= image_tag("preloader.gif", size: "50") %>
|
||||
<div>Posting your query.</div>
|
||||
</div>
|
||||
<% else %>
|
||||
<h4> Ticket is already opened. </h4>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% else %>
|
||||
<div>
|
||||
Error in fetching ticket.
|
||||
</div>
|
||||
<% end %>
|
||||
<script type="text/javascript">
|
||||
var fv = new FormValidator($("#reopen-form"));
|
||||
$("#reopen-form-submit").on("click",function(){
|
||||
for (instance in CKEDITOR.instances) {
|
||||
CKEDITOR.instances[instance].updateElement();
|
||||
}
|
||||
if(fv.isFormValidated()){
|
||||
$("#form_container").hide();
|
||||
$("#ticket_loader").show();
|
||||
fv.form.ajaxSubmit({
|
||||
success : function(data){
|
||||
setTimeout(function(){
|
||||
if(fv.form.attr("for") == "query"){
|
||||
$("#form_container").remove();
|
||||
window.location.href = window.location.pathname;
|
||||
}else{
|
||||
fv.reset();
|
||||
for (instance in CKEDITOR.instances) {
|
||||
CKEDITOR.instances[instance].setData("");
|
||||
}
|
||||
$("#form_container").show();
|
||||
$("#response-container").append(data);
|
||||
}
|
||||
$("#ticket_loader").hide();
|
||||
},500)
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
$(".reopen-back-btn").on("click",function(){
|
||||
for (instance in CKEDITOR.instances) {
|
||||
CKEDITOR.instances[instance].updateElement();
|
||||
}
|
||||
if(fv.form.find("textarea").val() == ""){
|
||||
window.history.back();
|
||||
}else if(confirm("Are you sure, you want to discard changes?")){
|
||||
window.history.back();
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
})
|
||||
|
||||
$(".ticket-category-select-option").on("click",function(){
|
||||
var el = $(this);
|
||||
if(confirm("Are you sure?")){
|
||||
window.location.href = window.location.pathname + "/changecategory?category_id=" + el.data("category-id");
|
||||
}
|
||||
return false;
|
||||
})
|
||||
$("#toggle-urgent").on("click",function(){
|
||||
var el = $(this),
|
||||
mark_urgent = !el.hasClass("active");
|
||||
$.ajax({
|
||||
url : el.attr("href"),
|
||||
type : "post",
|
||||
data : {"mark_urgent" : mark_urgent},
|
||||
dataType : "json"
|
||||
}).done(function(response){
|
||||
if(response.success){
|
||||
if(mark_urgent){
|
||||
if(response.can_make_urgent){
|
||||
$("#ticket-urgent-marker").css("background-color","#C61C2D");
|
||||
el.addClass("active");
|
||||
}else{
|
||||
alert("Urgent quota for this category is already over.");
|
||||
}
|
||||
}else{
|
||||
$("#ticket-urgent-marker").css("background-color","#2980b9");
|
||||
el.removeClass("active");
|
||||
}
|
||||
}
|
||||
})
|
||||
return false;
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,47 @@
|
|||
<div id="index_table">
|
||||
<h3><%= @category.title %></h3>
|
||||
<% content_for :page_specific_css do %>
|
||||
<%= stylesheet_link_tag "tickets" %>
|
||||
<% end %>
|
||||
<div class="category_ticket_wrap">
|
||||
<% if !@category.nil? %>
|
||||
<div>
|
||||
<h3>
|
||||
<%= @category.title %><%= " - history" if params[:type] == "history" %>
|
||||
<div class="search-wrap">
|
||||
<a href="#" id="serach-btn" style="font-size:20px;"><i class="icons-search"></i></a>
|
||||
<% if params[:keywords].present? %>
|
||||
<a href="/admin/tickets/category/<%= @category.id.to_s %><%= "?type=history" if params[:type] == "history" %>" style="font-size:20px;"><i class="icons-cycle"></i></a>
|
||||
<span>Searched for <b><i><%= params[:keywords] %></i></b></span>
|
||||
<% end %>
|
||||
<span class="search-box" style="display:none;">
|
||||
<form action="<%= request.original_fullpath %>" method="get" id="search-form">
|
||||
<select id="smart-field-select" style="width:100px;">
|
||||
<option value="">general</option>
|
||||
<% @smart_search_fields.each do |ssf| %>
|
||||
<option value="<%= ssf %>"><%= ssf %></option>
|
||||
<% end %>
|
||||
</select>
|
||||
<input type="text" placeholder="Search" style="width:0;" name="keywords" />
|
||||
<% if params[:type] == "history" %>
|
||||
<input type="hidden" name="type" value="history" />
|
||||
<% end %>
|
||||
</form>
|
||||
</span>
|
||||
</div>
|
||||
</h3>
|
||||
<% h = request.original_fullpath.split("?")[1] %>
|
||||
<% if params[:type] == "history" %>
|
||||
<% h = h.gsub("type=history","").chomp("&") %>
|
||||
<span style="position:relative;margin-top:-30px;" class="pull-right"><a href="/admin/tickets/category/<%= @category.id.to_s %><%= h != ""? "?#{h}" : "" %>">View current</a></span>
|
||||
<% else %>
|
||||
<% h = h.nil? ? "type=history" : "#{h}&type=history" %>
|
||||
<span style="position:relative;margin-top:-30px;" class="pull-right"><a href="/admin/tickets/category/<%= @category.id.to_s %>?<%= h %>">View history</a></span>
|
||||
<% end %>
|
||||
</div>
|
||||
<% else %>
|
||||
<div>
|
||||
<h3>Category Not found!</h3>
|
||||
</div>
|
||||
<% end %>
|
||||
<table class="table main-list">
|
||||
<thead>
|
||||
<tr class="sort-header">
|
||||
|
@ -9,17 +51,19 @@
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% if !@tickets.nil? %>
|
||||
<% if !@tickets.nil? && @tickets.count > 0 %>
|
||||
<%= render :partial => "ticket_by_c", :collection => @tickets %>
|
||||
<% else %>
|
||||
<tr><td colspan="5">No tickets for <%= @category.title rescue "" %></td></tr>
|
||||
<tr><td colspan="7" style="text-align:center;">No tickets.</td></tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
<% if !@tickets.nil? && @tickets.count > 0 %>
|
||||
<%=
|
||||
content_tag :div, class: "bottomnav clearfix" do
|
||||
content_tag :div, paginate(@tickets), class: "pagination pagination-centered"
|
||||
end
|
||||
%>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript" src="/assets/search.js"></script>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
en:
|
||||
tickets:
|
||||
tickets: Tickets
|
||||
my_tickets: My Tickets
|
||||
all: All
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
zh_tw:
|
||||
tickets:
|
||||
tickets: Tickets
|
||||
my_tickets: My Tickets
|
||||
all: All
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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}",
|
||||
|
|
Loading…
Reference in New Issue