Colocando em prática
Objetivo¶
Nesta seção, vamos colocar em prática o uso dos QSM, aplicando seus conceitos e ferramentas para implementar o exemplo apresentado no Gerenciamento de Tickets.
Criar Tipo de Caso¶
Primeiramente, é necessário criar um ticketType, que servirá como base para o nosso caso de uso.
-
Acesse a página que lista todos os tipos de tickets disponíveis em
/ticketTypes
. -
Para criar um formulário vinculado ao ticket, defina campos para que o usuário descreva o problema. Também é possível configurar os status do ticket, como, por exemplo: Pendente, Em andamento, Cancelado e Concluído.
Criar Fila¶
Em segundo lugar, é necessário criar uma fila para definir o setor ou a prioridade em que o ticket será alocado.
-
Acesse a página de filas disponíveis em
/groups/fila?groupTypeName=fila
.
Criar Categoria¶
Em seguida, é necessário criar uma categoria que especificará a qual grupo o ticket criado pertencerá.
-
Acesse a página de categorias disponíveis em
/categories
. -
Todo ticket criado por meio dessa categoria será direcionado automaticamente para a fila definida.
-
É possível criar um formulário específico tanto para o ticket quanto para a categoria.
Criar Catálogo¶
Após configurar o ticketType
, fila e categorias, o próximo passo é criar um catálogo (catalog), que pode incluir um conjunto de serviços ou um único serviço.
- Acesse a página de Catalog e siga as etapas até a seção 1.6.
- Após criar o catálogo, ele poderá ser acessado pela URL
/app/catalog/meu_catalogo
.
Criar Conjunto de Serviços¶
Agora, você utilizará todas as configurações feitas anteriormente, como ticketType
e categorias.
-
Acesse seu catálogo de serviços e clique em Adicionar item.
-
Escolha a opção Conjunto de Serviços e preencha os dados necessários, como nome, resumo dos serviços e imagem.
Criar Serviço¶
Dentro do conjunto de serviços criado, é possível adicionar serviços específicos.
-
Acesse o conjunto criado e clique para gerenciar os serviços.
-
Escolha um serviço, associando-o ao
ticketType
e à categoria desejada. Cada serviço deve ter uma categoria única, com um formulário correspondente. -
Configure os campos a serem exibidos para o usuário. Se o formulário já inclui descrição e anexo, essas opções não precisam ser selecionadas.
Após essas configurações, você terá um formulário acessível ao clicar no serviço cadastrado.
Ao criar um ticket, você será redirecionado para a tela de informações detalhadas do ticket. Nessa tela, é possível visualizar e gerenciar todos os dados relevantes.
Para personalizar a tela conforme as necessidades da sua organização, siga o exemplo abaixo:
Visão geral do atendente¶
{
"hooks": {
"ticketLoaded": "{{ }}"
},
"mainTab": {
"icon": "mdi-ticket",
"showIcon": true,
"hideClose": false,
"iconColor": "#757575"
},
"extraTabs": [
{
"path": "detailsOnly",
"slug": "detailsOnly",
"text": "Detalhes",
"TicketDetails": {
"Header": {
"hideName": true,
"hideText": true
},
"saveBtn": "Salvar informações",
"hideBody": true,
"saveFormsCallback": "{{ () => { $fetchTicket() } }}",
"TicketPrimaryInfos": {
"hideQueue": true,
"hideStatus": true,
"hidePriority": true,
"readOnlyType": true,
"readOnlyStatus": true,
"readOnlyCategory": true
},
"hideTicketPrimaryInfos": true,
"hideAdditionalInfoTitle": true
}
},
{
"path": "history",
"slug": "history",
"text": "Eventos",
"TicketActions": {}
},
{
"path": "relatedResources",
"slug": "relatedResources",
"text": "Recursos Relacionados"
},
{
"path": "approvals",
"slug": "approvals",
"text": "Aprovações"
}
],
"sideBarTabs": [
{
"icon": "mdi-information",
"path": "recordInfo",
"slug": "recordInfo",
"text": "Informações",
"useGroupAssoc": false,
"whereUserSearch": {
"userProfileId": {
"not": 100007
}
},
"enableChangeAssignedToUserToAnyUser": "(ticketAgentOverview){{ !$isCancelled && !$isClosed && !$isSolved }}"
},
{
"icon": "mdi-attachment",
"path": "attachments",
"slug": "attachments",
"text": "Anexos"
}
],
"AgentOverviewHeader": {
"Slot1": {
"children": [
{
"slug": "ticketPrimaryInfos",
"props": {
"ticket": "{{ $ticket }}",
"configs": {
"infos": [
{
"slug": "text",
"text": "Status",
"label": "status",
"modifier": {
"value": "{{ $ticket?.status || 'Não identificado' }}"
},
"modifierSlug": "text"
},
{
"slug": "text",
"text": "Categoria",
"label": "categoria",
"modifier": {
"value": "{{ $ticket?.Category?.name || 'Não identificado' }}"
},
"modifierSlug": "text"
},
{
"slug": "text",
"text": "Criado em",
"label": "criado em",
"modifier": {
"value": "{{ $$moment($ticket?.createdAt).format('DD/MM/YYYY [às] HH:mm') || 'Não identificado' }}"
},
"modifierSlug": "text"
},
{
"slug": "text",
"text": "Responsável",
"label": "responsavel",
"modifier": {
"value": "{{ $ticket?.ticketAssignedToUser?.name || 'Não identificado' }}"
},
"modifierSlug": "text"
},
{
"slug": "text",
"text": "Última atualização",
"label": "ultima atualizacao",
"modifier": {
"value": "{{ $$moment($ticket?.updatedAt).format('DD/MM/YYYY [às] HH:mm') || 'Não identificado' }}"
},
"modifierSlug": "text"
}
]
}
}
}
]
},
"title": "{{ 'Chamado ' + $ticket?.id }}",
"hideStatus": true,
"titleCaption": "Solicitação associada ao",
"hideCreatedAt": true,
"oldActionButtons": [
{
"icon": "mdi-delete",
"text": "Remover chamado",
"type": "general",
"color": "red",
"dense": true,
"action": "{{ (input) => { return (async () => { await $preDeleteTicket($ticket); $closeTab($ticket) })() } }}",
"outlined": true,
"condition": "{{ (input) => { return $userCanDeleteTicket } }}",
"depressed": true,
"aksConfirmation": false,
"hideTextOnDesktop": true
},
{
"icon": "mdi-download",
"text": "Download",
"type": "general",
"dense": true,
"action": "{{ (input) => { return (async () => { await $downloadTicket() })() } }}",
"outlined": true,
"condition": "{{ (input) => { return true } }}",
"depressed": true,
"aksConfirmation": false,
"hideTextOnDesktop": true,
"disableAutomaticRefresh": true
},
{
"icon": "mdi-close",
"text": "Cancelar chamado",
"type": "general",
"dense": true,
"action": "{{ (input) => { return (async () => { await $cancelTicket() })() } }}",
"outlined": false,
"textProp": true,
"condition": "{{ (input) => { return $userCanCancelTicket } }}",
"depressed": true,
"aksConfirmation": false,
"disableAutomaticRefresh": true
},
{
"icon": "mdi-account",
"text": "Pegar para mim",
"type": "general",
"color": "primary",
"dense": true,
"action": "{{ (input) => { return (async () => { await $updateTicket({id: $ticket.id, assignedToUser: $me?.id, status: 'Em andamento' }) })() } }}",
"outlined": false,
"condition": "{{ (input) => { return !$assignedToUserIsMe && !$isCancelled && !$isClosed && !$isSolved } }}",
"depressed": true,
"dialogText": "Deseja ser o atendente responsável por esse chamado?",
"dialogTitle": "Pegar para mim",
"aksConfirmation": true
},
{
"icon": "mdi-human-queue",
"text": "Devolver para a fila",
"type": "general",
"color": "primary",
"dense": true,
"action": "{{ (input) => { return (async () => { await $updateTicket({id: $ticket.id, assignedToUser: null, status: 'pendente' }) })() } }}",
"outlined": true,
"condition": "{{ (input) => { return $enableReturnToQueue } }}",
"depressed": true,
"dialogText": "Deseja devolver esse chamado para a fila?",
"dialogTitle": "Devolver para a fila",
"aksConfirmation": true
},
{
"icon": "check",
"text": "Resolver",
"type": "general",
"color": "primary",
"dense": true,
"action": "{{ (input) => { return (async () => { await $updateTicket({id: $ticket.id, status: 'Resolvido'}) })() } }}",
"outlined": false,
"condition": "{{ (input) => { return ($enableChangeStatus && $ticket.status === 'Em andamento') } }}",
"depressed": true,
"dialogText": "Após essa ação, o chamado ficará com status \"Resolvido\". Deseja realizar esse procedimento?",
"dialogTitle": "Resolver chamado",
"aksConfirmation": true
}
],
"allowResizeHeader": false,
"groupedButtonName": "Realizar ação",
"maxVisibleButtons": 3
}
}
Criar workspace¶
Se desejar, você pode criar um workspace para listar todos os tickets de um tipo ou categoria específicos. Siga o tutorial abaixo para configurar o seu:
-
Acesse /databases e procure por workspaces, clique em Acessar database
-
Você será redirecionado para a tela de listagem de workspaces, onde também é possível criar novos. Clique em Novo e, em seguida, selecione individualmente para iniciar a criação
-
Em seguida, será exibido um diálogo onde você poderá definir o path e o nome do seu workspace, além de configurar algumas opções básicas. O valor padrão para o path é tickets, enquanto o nome será o identificador de referência dentro do sistema.
-
Configurações básica para workspace:
{
"tabs": [
{
"path": "ticketTable",
"slug": "ticketTable",
"text": "Chamados em aberto",
"filter": {
"status": [
"pendente"
]
},
"tabTitle": "Pendente"
},
{
"path": "ticketTable",
"slug": "ticketTable",
"text": "Chamados em andamento",
"filter": {
"status": [
"Em andamento"
]
},
"tabTitle": "Em andamento"
},
{
"path": "ticketTable",
"slug": "ticketTable",
"text": "Chamados resolvidos",
"filter": {
"status": [
"Resolvido"
]
},
"tabTitle": "Resolvidos"
},
{
"path": "ticketTable",
"slug": "ticketTable",
"text": "Todos os chamados",
"filter": {},
"tabTitle": "Todos"
}
],
"defaultTab": {
"order": [
[
"createdAt",
"DESC"
]
],
"fields": [
{
"name": "id",
"label": "id",
"sortable": true
},
{
"name": "solicitante",
"label": "Solicitado por"
},
{
"name": "category",
"label": "Categoria"
},
{
"name": "status",
"label": "Status",
"sortable": true
},
{
"name": "createdAt",
"type": "date",
"label": "Criado em",
"convert": "{{ (input) => { return $$moment(input).format('LLL') } }}",
"sortable": true
}
],
"params": {
"includeQueue": false,
"additionalInfos": [
{
"ticketTypeId": id do ticketType
}
],
"columnsToSearch": [
"id",
"status"
],
"includeSharedGroup": false,
"includeTicketGoals": false,
"includeAdditionalInfos": true
},
"attributes": [
"id",
"body",
[
"TicketType.name",
"type"
],
[
"ticketRecipient.name",
"solicitante"
],
[
"ticketAssignedToUser.name",
"ticketAssignedToUserName"
],
[
"ticketCreator.name",
"ticketCreatedByName"
],
[
"Category.name",
"category"
],
[
"TicketType.id",
"ticketTypeId"
],
"priority",
"description",
"status",
"createdAt",
"updatedAt",
"isAppointment",
"scheduleDate",
"duration"
],
"filterConfig": {
"hideQueue": true,
"hideCategory": true,
"hideCreatedBy": true,
"hideRecipient": true,
"hideCreatedByt": true,
"hideTicketType": true,
"hideSectorTicket": true,
"hideSearchByTitle": true,
"assignedToUserWhere": {},
"listAvailableToOrder": [
{
"name": "Tempo de criação",
"value": "created_at"
},
{
"name": "Última atualização",
"value": "updatedAt"
}
],
"statusFromTicketTypes": [ id do ticketType ]
}
},
"ticketAgentOverview": {
"general": {
"extraTabsMaxWidth": 70,
"extraTabsMinWidth": 20,
"isExtraTabsResize": false,
"initialExtraTabsWidth": 65
},
"listOneParams": {
"additionalInfos": [
{
"ticketTypeId": id do ticketType
}
]
}
}
}
Criar menu¶
Por fim, para exibir a tela do workspace no menu lateral ou superior:
- Acesse /menu.
- Escolha o tipo de menu e o perfil de usuário que terá acesso. Se você é administrador, selecione o perfil correspondente ou escolha outro conforme necessário.
-
Depois aperte o botão de Novo
-
Selecione o tipo de menu. Para um menu suspenso, escolha uma categoria; caso contrário, opte por uma página. Neste caso, vamos selecionar uma página.
-
Em seguida, crie um menu e configure-o para renderizar o workspace que foi criado.
-
Uma aba lateral de edição será aberta, onde você poderá definir o nome do menu, a página (o workspace) e a path do workspace criado, no fim da configuração aperte o botão salva
-
Ao final, o menu lateral estará configurado corretamente.