Pular para conteúdo

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.

  1. Acesse a página que lista todos os tipos de tickets disponíveis em /ticketTypes.

    Criar um ticketType Configurando ticketType

  2. 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 formulário adicional e status Salvando formulário

Criar Fila

Em segundo lugar, é necessário criar uma fila para definir o setor ou a prioridade em que o ticket será alocado.

  1. Acesse a página de filas disponíveis em /groups/fila?groupTypeName=fila.

    Criar uma fila Salvando fila

Criar Categoria

Em seguida, é necessário criar uma categoria que especificará a qual grupo o ticket criado pertencerá.

  1. Acesse a página de categorias disponíveis em /categories.

    Criar uma categoria Configurando uma categoria

  2. Todo ticket criado por meio dessa categoria será direcionado automaticamente para a fila definida.

    Adicionando a categoria a uma fila

  3. É possível criar um formulário específico tanto para o ticket quanto para a categoria.

    Adicionando um formulário à categoria Configurando formulário da categoria Salvando categoria

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.

  1. Acesse a página de Catalog e siga as etapas até a seção 1.6.
  2. 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.

  1. Acesse seu catálogo de serviços e clique em Adicionar item.

    Adicionar item ao catálogo

  2. Escolha a opção Conjunto de Serviços e preencha os dados necessários, como nome, resumo dos serviços e imagem.

    Tipo de Serviço no catálogo Configurando conjunto criado

Criar Serviço

Dentro do conjunto de serviços criado, é possível adicionar serviços específicos.

  1. Acesse o conjunto criado e clique para gerenciar os serviços.

    Gerenciar conjunto criado

  2. Escolha um serviço, associando-o ao ticketType e à categoria desejada. Cada serviço deve ter uma categoria única, com um formulário correspondente.

    Escolhendo um ticketType Escolhendo uma categoria

  3. 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.

    Configurando serviço criado

Após essas configurações, você terá um formulário acessível ao clicar no serviço cadastrado.

Acessando Serviço

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
  }
}
Para mais informações sobre cada propriedade e para visualizar detalhes sobre elas, consulte a Visão geral do atendente.

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:

  1. Acesse /databases e procure por workspaces, clique em Acessar database

    Pesquisar por workspace

  2. 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

    Criar workspace

  3. 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. Criando workspace

  4. 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
        }
      ]
    }
  }
}
Para mais informações sobre cada propriedade e para visualizar detalhes sobre elas, consulte o Workspace.

Criar menu

Por fim, para exibir a tela do workspace no menu lateral ou superior:

Menu

  1. Acesse /menu.
  2. 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.
  3. Depois aperte o botão de Novo Criando um menu

  4. 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.

    Escolhendo um tipo de menu

  5. Em seguida, crie um menu e configure-o para renderizar o workspace que foi criado. Editando o menu

  6. 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 Salvando menu

  7. Ao final, o menu lateral estará configurado corretamente. Menu configurado