Capítulo 7: Adicionar funcionalidade à aplicação
Kiana e Maria estão entusiasmadas por mostrar a aplicação de gestão do inventário a Caleb, o técnico no terreno. Caleb gosta da aplicação, mas sugere adicionar alguma funcionalidades adicionais à interface de utilizador para facilitar a sua utilização. Especificamente, Caleb gostaria de ser capaz de:
Adicionar uma fotografia do trabalho feito numa caldeira ou unidade de ar condicionado, e adicioná-la aos detalhes do compromisso no ecrã Editar Compromisso. Esta imagem pode revelar-se útil como prova documental das reparações realizadas. Atualmente, o ecrã Editar Compromisso permite ao utilizador adicionar uma imagem ao compromisso, mas a imagem não é guardada, uma vez que esta funcionalidade ainda não foi totalmente implementada. Esta omissão deve-se a Kiana e Preeti precisarem de determinar o melhor lugar para armazenar os dados de imagens. Caleb gostaria que esta funcionalidade fosse adicionada o mais rapidamente possível.
Veja um histórico dos compromissos concluídos para um cliente, para acompanhar as reparações que foram solicitadas e monitorizar quaisquer problemas em curso que possam exigir que os técnicos sejam repetidamente chamados.
Encomende peças a partir do ecrã Detalhes das Peças.
Além disso, o controlo Imagem no ecrã Detalhes das Peças apresenta as imagens armazenadas num URL especificado. Atualmente, os URLs nos dados são simplesmente marcadores de posição. Tal como as fotografias para o ecrã de compromisso, Kiana e Preeti precisam determinar o melhor local para armazenar imagens para que estejam disponíveis para a aplicação.
Adicionar uma fotografia a um compromisso
As fotografias precisam de ser armazenadas em algum lugar acessível pela aplicação. Por motivos de desempenho e segurança, Preeti não quer que as fotografias sejam guardadas no OneDrive ou na Base de Dados SQL do Azure. Em vez disso, decidem usar o Armazenamento de Blobs do Azure. O Armazenamento de Blobs está otimizado para conter grandes objetos binários, e é robusto, com segurança incorporada. O Power Apps tem um conector que permite o acesso ao Armazenamento de Blobs. Maria sugere adicionar um novo ecrã para tirar fotografias, melhorando a experiência de utilizador para Caleb.
Mais informações: Armazenamento de Blobs do Azure
Preeti cria a conta de Armazenamento de Blobs a partir do portal do Azure seguindo estes passos:
No Portal do Azure, na página Home page, selecione + Criar um recurso. Na caixa de texto Pesquisar no Marketplace, introduza Conta de armazenamento e selecione Enter.
Na página Conta de armazenamento, selecione Criar.
Na página Criar conta de armazenamento, introduza os seguintes detalhes e selecione Rever + criar:
- Subscrição: selecione a sua subscrição
- Grupo de recursos: webapi_rg
- Nome da conta de armazenamento: forneça um nome globalmente único e anote-o para mais tarde
- Localização: selecione a localização mais próxima
- Desempenho: Standard
- Tipo de conta: BlobStorage
- Replicação: RA-GRS
Na página de validação, selecione Criar e aguarde enquanto a conta de armazenamento é aprovisionada.
Vá para página para a nova conta de armazenamento.
Na página Descrição geral, selecione Contentores.
Na página Contentores, selecione + Contentor. Crie um novo contentor denominado fotografias e selecione Criar. Altere Nível de acesso público para Blob.
Regresse à página Descrição geral para a conta de armazenamento e, em definições, selecione Teclas de acesso. Na página Chaves de acesso, selecione Mostrar teclas. Tome nota do valor da chave para key1.
Preeti dá o nome e a chave da conta de armazenamento a Kiana, que usa esta informação para criar um conector personalizado para a aplicação seguindo estes passos:
Inicie sessão no Power Apps.
No painel esquerdo, expanda Dados e selecione Ligações. As ligações existentes utilizadas pela aplicação devem ser listadas. Selecione + Nova ligação.
Na página Nova ligação, desloque-se para baixo, selecione Ligações, selecione Armazenamento de Blobs do Azure e, em seguida, selecione Criar.
Na caixa de diálogo Armazenamento de Blobs do Azure, introduza o nome da conta de armazenamento e a chave de acesso que Preeti forneceu e, em seguida, selecione Criar.
Aguarde enquanto a nova ligação é criada. Deve aparecer na lista de ligações.
Maria pode usar esta ligação ao Armazenamento de Blobs na aplicação para guardar e obter imagens fotográficas. A primeira tarefa de Maria é adicionar a ligação à aplicação seguindo estes passos:
Abra a aplicação VanArsdelApp para edição no Power Apps Studio.
No painel Dados, selecione Adicionar dados, procure o conector Armazenamento de Blobs do Azure e, em seguida, selecione o conector.
Na caixa de diálogo Armazenamento de Blobs do Azure, selecione o conector Armazenamento de Blobs do Azure para adicioná-lo à sua aplicação.
A tarefa seguinte de Maria é adicionar um ecrã que permita a um técnico ou engenheiro guardar uma fotografia. Maria decide adicionar um novo ecrã com um controlo Picture. Quando a aplicação é executada num dispositivo móvel, este controlo pode integrar-se na câmara para permitir ao técnico tirar uma fotografia. Noutros dispositivos, este controlo pede ao utilizador para, em alternativa, carregar um ficheiro de imagem. Maria adiciona uma ligação para este novo ecrã a partir do ecrã EditAppointment ao seguir estes passos:
No menu Inserir, selecione Novo ecrã e, em seguida, selecione o modelo Deslocável.
No painel Vista de árvore, selecione o novo ecrã e mude o seu nome para TakePhoto.
Altere a propriedade Texto do controlo LblAppNameX neste ecrã para Tirar uma fotografia.
Elimine o controlo CanvasX do ecrã.
No menu Inserir, a partir da lista pendente Suporte de dados, selecione Adicionar imagem para criar um novo controlo Imagem.
Nota
O controlo Imagem é, na verdade, um componente personalizado composto que permite ao utilizador adicionar uma imagem ao ecrã e apresentar os resultados.
Redimensione e reposicione o controlo Imagem para ocupar o corpo do ecrã.
No painel Vista de árvore, selecione o controlo IconBackarrowX no ecrã AppointmentDetails e selecione Copiar.
No menu Vista de árvore, clique com o botão direito do rato no ecrã TakePhoto e selecione Colar. O controlo IconBackArrowX será adicionado ao ecrã.
Desloque o controlo IconBackArrowX para a parte superior esquerda da barra de cabeçalho.
No painel Vista de árvore, selecione o controlo IconBackArrowX no ecrã TakePhoto. No painel direito, no separador Avançadas, modifique a propriedade de ação OnSelect para Navigate(EditAppointment, ScreenTransition.None).
Adicione um novo controlo do ícone Guardar à parte superior direita da barra de cabeçalho. Defina a propriedade Visível deste controlo como If(IsBlank(AddMediaButton1.Media), false, true).
Esta definição torna o ícone Guardar invisível se o utilizador não tiver selecionado uma imagem.
Altere a fórmula na propriedade de ação OnSelect do controlo de ícone Guardar para o seguinte.
Set(ImageID, GUID() & ".jpg"); AzureBlobStorage.CreateFile("photos", ImageID, AddMediaButton1.Media); Patch(appointmentsCollection, LookUp(appointmentsCollection,id=BrowseAppointmentsGallery.Selected.id), {imageUrl:"https://myappphotos.blob.core.windows.net/photos/" & ImageID}); Navigate(EditAppointment,ScreenTransition.Cover);
Substitua <storage account name> pelo nome da conta de armazenamento do Azure que Preeti criou.
Este código carrega a imagem para o contentor fotografias no Armazenamento de Blobs. É atribuído a cada imagem um nome de ficheiro exclusivo. A função Patch atualiza a propriedade imageUrl no registo de compromissos com o URL da imagem no Armazenamento de Blobs.
No painel Vista de árvore, expanda o controlo AddMediaWithImageX. Modifique a propriedade Imagem do controlo UploadedImageX e defina-a como AppointmentImage.
AppointmentImage é uma variável que será povoada com uma imagem carregada pelo utilizador ou como resultado de tirar uma fotografia. Mais tarde, inicialize esta variável no ecrã EditAppointment.
No painel Vista de árvore, selecione o controlo AddMediaButtonX. Defina a propriedade UseMobileCamera deste controlo como true. Defina a propriedade de ação OnChange do controlo para o seguinte.
Set(AppointmentImage, AddMediaButton1.Media)
Esta fórmula altera a variável NomeaçãoImage para fazer referência à nova imagem. O controlo UploadedImageX apresentará esta imagem.
No painel Vista de árvore, selecione o ecrã EditAppointment.
Expanda o controlo EditFormX. No controlo Image_DataCardX, remova o controlo AddPictureX.
Selecione o controlo ImageX. Altere as propriedades seguintes :
- Imagem: Parent.Default
- X: 30
- Y: DataCardKeyX.Y + DataCardKeyX.Height + 150 (em que DataCardKeyX é o cartão de dados que contém o controlo ImageX)
- Largura: Parent.Width - 60
- Altura: 400
Nota
O controlo Imagem descerá abaixo da parte inferior do ecrã, mas será adicionada automaticamente uma barra de deslocação para permitir a visualização da imagem.
Adicione um ícone de Câmara ao cartão de dados e, em seguida, posicione-o entre a etiqueta Imagem e o controlo ImageX. Altere o nome do controlo para CameraIcon.
Nota
Certifique-se de que seleciona o controlo de ícone Câmara, não o controlo Suporte de Dados da Câmara.
Defina a propriedade de ação OnSelect do controlo CameraIcon para o seguinte.
Set(AppointmentImage, SampleImage); Navigate(TakePhoto, ScreenTransition.None);
Quando o utilizador seleciona este ícone, é aberto o ecrã TakePhoto, onde poderá tirar uma fotografia ou carregar uma imagem. A imagem inicial apresentada será a imagem de exemplo predefinida.
Para testar a aplicação, faça o seguinte:
No painel Vista de árvore, selecione o ecrã Home page.
Selecione F5 para pré-visualizar a aplicação.
No ecrã Home page, selecione Compromissos.
No ecrã de procura, selecione qualquer compromisso.
No ecrã de detalhes para o compromisso, selecione o ícone de edição no cabeçalho do ecrã.
No ecrã de edição, selecione o ícone Câmara para a imagem.
Verifique se aparece o ecrã Tirar uma fotografia.
Selecione Alterar Imagem e carregue uma fotografia à sua escolha (ou tire uma fotografia, se estiver a executar a aplicação num dispositivo móvel).
Selecione Guardar. Verifique se a imagem aparece na página de detalhes e, em seguida, selecione o ícone de marca para voltar a guardar as alterações na base de dados.
Feche a janela de pré-visualização e regresse ao Power Apps Studio.
Apresentar imagens de peças
Depois de determinar que o Armazenamento de Blobs é uma localização ideal para guardar as imagens associadas aos compromissos, Preeti e Kiana decidem que devem usar a mesma abordagem para armazenar as imagens das peças. Uma vantagem chave desta abordagem é a de não exigir quaisquer modificações à aplicação. A aplicação reutiliza a mesma conta de armazenamento e a mesma ligação. Como exercício de migração separado, pode ser feito o seguinte:
Crie um novo contentor do Armazenamento de Blobs.
Carregue as imagens de peças para este contentor.
Altere as referências ImageUrl na tabela Peças na base de dados InventoryDB para o URL de cada imagem.
A aplicação obterá automaticamente o novo URL para cada imagem de peça e o controlo Imagem no ecrã PartDetails apresentará a imagem.
Monitorizar o histórico de compromissos de um cliente
Maria acha que conseguir ver rapidamente todo o histórico de visitas anteriores de um técnico a um cliente poderia ser adicionado à aplicação ao criar um componente personalizado. Ao trabalhar com Caleb sobre a informação que querem ver, Maria esboça uma estrutura simples que inclui as notas e a data de cada visita.
Olhando para os dados, Maria acredita que um controlo Galeria é a melhor forma de apresentar os dados de tabelas num ecrã.
Maria cria o componente personalizado da seguinte forma:
Através do Power Apps Studio, no painel Vista de árvore, selecione Componentes e, em seguida, selecione + Novo componente.
É criado um novo componente em branco chamado Component1. Mude o nome do componente para DateHistoryComponent.
No menu Inserir, selecione Galeria e, em seguida, escolha o modelo de galeria Altura flexível em branco.
Mova o controlo Galeria e redimensione-o para preencher o componente personalizado.
Selecione Adicionar um item do painel de inserção e, em seguida, selecione Etiqueta de texto.
No painel Vista de árvore, mude o nome do controlo de etiqueta para NotesLabel. Defina a propriedade Capacidade excedida como Overflow.Scroll. Esta definição permite ao controlo apresentar várias linhas de texto e permite ao utilizador deslocar-se nelas. Defina as seguintes propriedades para poder posicionar e dimensionar o controlo:
- LineHeight: 2
- X: 28
- Y: 18
- Largura: 574
- Altura: 140
Adicione uma segunda etiqueta de texto ao controlo. Mude o nome deste controlo para DateLabel e defina as seguintes propriedades:
- LineHeight: 2
- X: 28
- Y: 174
- Largura: 574
- Altura: 70
Para ver como será o controlo quando inserido na aplicação e apresentado com o respetivo tema, no painel Vista de árvore, selecione DateHistoryComponent. No painel direito, no separador Avançadas, selecione o campo Preencher e altere a cor para RGBA(0, 0, 0, 1).
No painel Inserir, expanda Formas e adicione um controlo Retângulo ao componente personalizado. Defina as propriedades seguintes para este controlo:
- X: 0
- Y: 273
- Largura: Parent.Width
- Altura: 2
Este controlo funciona como um separador entre os registos apresentados na galeria.
Maria está familiarizada com a adição de controlos a ecrãs e com a compilação de aplicações com o Power Apps. No entanto, os componentes reutilizáveis não funcionam da mesma forma. Kiana descreveu a Maria que, para poderem usar dados num componente personalizado, devem ser adicionadas algumas propriedades de entrada personalizadas. Kiana também explicou que Maria precisa de fornecer dados de exemplo para estas propriedades para referenciar os campos de dados nos controlos do componente, da seguinte forma:
No painel Vista de árvore, selecione DateHistoryComponent. No painel direito, no separador Propriedades, selecione Nova propriedade personalizada.
Na caixa de diálogo Nova propriedade personalizada, especifique os seguintes valores e selecione Criar:
- Nome a apresentar: Dados
- Nome: Dados
- Descrição: A tabela de compromissos para um cliente, mostrando as notas e as datas
- Tipo de propriedade: Entrada
- Tipo de dados: Tabela
- Gerar onReset quando o valor mudar: deixar em branco
Para alterar os dados de exemplo apresentados pelo controlo, selecione a nova propriedade personalizada Dados. No campo de fórmula, introduza Table({Notas: "Texto do campo de notas de exemplo.", 'Data do Compromisso': Text(Today())}).
No painel Vista de árvore, selecione o controlo GaleriaX em DateHistoryComponent e mude o nome para AppointmentHistory.
No painel direito, no separador Avançadas, defina a propriedade Itens do controlo Galeria AppointmentHistory como Parents.Data.
Selecione o controlo NotesLabel. No painel direito no separador Avançadas, altere a propriedade Texto para ThisItem.Notes, e altere a propriedade Tamanho para 20.
Nota
A propriedade Tamanho especifica o tamanho do tipo de letra para o texto apresentado pelo controlo.
Selecione o controlo DateLabel para alterar a propriedade Texto para ThisItem.'Appointment Date' e altere a propriedade Tamanho para 20. Os campos no componente personalizado devem apresentar os dados de exemplo.
O componente personalizado está concluído. Maria cria um novo ecrã para apresentar o histórico de compromissos para um cliente utilizando este componente, da seguinte forma:
No painel Vista de árvore, selecione o separador Ecrãs.
Expanda o ecrã BrowseAppointments, expanda o controlo BrowseAppointmentsGallery e selecione o controlo Body1_1. No menu Inserir, selecione Ícones e, em seguida, o ícone de Lista de detalhes.
Altere o nome do controlo de ícone para ViewAppointments.
No menu Vista de árvore, selecione o controlo BrowseAppointmentsGallery. No painel direito, no separador Avançadas, altere a propriedade TemplateSize para 220. Aumentar esta propriedade expande o espaço disponível na galeria.
Mova o ícone ViewAppointments para o espaço vazio sob o nome do cliente.
Selecione o controlo de ícone ViewAppointments. Defina a propriedade de ação OnSelect para a fórmula seguinte.
ClearCollect(customerAppointmentsCollection, FieldEngineerAPI.getapicustomeridappointments(ThisItem.customerId)); Navigate(AppointmentsHistoryScreen, ScreenTransition.Fade)
Esta fórmula preenche uma coleção denominada customerAppointmentsCollection com os compromissos para o cliente selecionado e, em seguida, move-se para AppointmentHistoryScreen para os apresentar. Crie este ecrã através dos seguintes passos.
No menu Inserir, selecione Novo ecrã e, em seguida, selecione o modelo Deslocável.
Altere o nome do novo ecrã para AppointmentHistoryScreen.
Elimine o controlo CanvasX que foi adicionado a este ecrã.
Selecione o controlo LblAppNameX neste ecrã. No painel direito, no separador Avançadas, altere a propriedade Texto para o seguinte.
"Appointments History for " & BrowseAppointmentsGallery.Selected.customer.name
Defina as seguintes propriedades para o controlo LblAppNameXpara ajustar a posição e o tamanho:
- X: 90
- Y: 0
- Largura: 550
- Altura: 140
Selecione o controlo RectQuickActionBarX e defina a propriedade Altura como 140.
Adicione um controlo de Ícone esquerdo ao cabeçalho do ecrã, à esquerda do título. Defina a propriedade de ação OnSelect para este controlo para Navigate(BrowseAppointments, Transition.None).
No menu Inserir, selecione Personalizado e, em seguida, selecione o DateHistoryComponent.
Mova e redimensione o componente para ocupar o corpo do ecrã, abaixo do título.
Defina as propriedades seguintes para este componente:
- Dados: customerAppointmentsCollection
- Data do Compromisso: startDateTime
- Notas: notas
Guardar a aplicação.
Para testar a aplicação, faça o seguinte:
No painel Vista de árvore, selecione o ecrã Home page.
Selecione F5 para pré-visualizar a aplicação.
No ecrã Home page, selecione Compromissos.
No ecrã de procura, selecione o ícone Lista de detalhes para qualquer compromisso.
Verifique se aparece o ecrã Histórico de Compromissos para o cliente selecionado.
Feche a janela de pré-visualização e regresse ao Power Apps Studio.
Encomendar peças
Um requisito chave do sistema consiste em permitir que um técnico encomende todas as peças necessárias durante a visita a um cliente. Se as peças estiverem em stock, deverá ser possível agendar outra visita para concluir a reparação na próxima data conveniente para o cliente. Se as peças estiverem esgotadas e tiverem de ser encomendadas, o técnico poderá dizê-lo ao cliente. Malik pode então marcar um compromisso com o cliente quando Maria recebe um aviso de que as peças chegaram ao armazém.
A parte de reservas da aplicação utiliza as tabelas na base de dados InventoryDB mostrada na seguinte imagem. A tabela Encomendas contém informações sobre encomendas de peças feitas. A tabela Reservas lista os pedidos de reserva que técnicos e os engenheiros fizeram por peças. A tabela Engenheiros fornece o nome e o número de contacto do engenheiro que fez a reserva, o que facilita a Maria, enquanto gestora do inventário, as consultas, se for necessário.
Para suportar esta funcionalidade, a Kiana tem de atualizar a API Web com um método que obtém o número de itens reservados para uma peça especificada, da seguinte forma:
Abra o projeto de API Web FieldEngineerApi no Visual Studio Code.
Adicione um ficheiro denominado Order.cs à pasta Modelos. Adicione o seguinte código a este ficheiro. A classe Encomendas monitoriza os detalhes das encomendas feitas para peças.
using System; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; namespace FieldEngineerApi.Models { public class Order { [Key] public long Id { get; set; } public long BoilerPartId { get; set; } public BoilerPart BoilerPart { get; set; } public long Quantity { get; set; } [Column(TypeName = "money")] public decimal TotalPrice { get; set; } [Display(Name = "OrderedDate")] [DataType(DataType.DateTime)] [DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}")] public DateTime OrderedDateTime { get; set; } public bool Delivered { get; set; } [Display(Name = "DeliveredDate")] [DataType(DataType.DateTime)] [DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}")] public DateTime? DeliveredDateTime { get; set; } } }
Adicione outro novo ficheiro denominado Reservation.cs à pasta Modelos e adicione o seguinte código a este ficheiro. A classe Reserva contém informações sobre o número de itens para uma determinada peça que estão atualmente reservados para outros clientes.
using System; using System.ComponentModel.DataAnnotations; namespace FieldEngineerApi.Models { public class Reservation { [Key] public long Id { get; set; } public long BoilerPartId { get; set; } public BoilerPart BoilerPart { get; set; } public int NumberToReserve { get; set; } public string EngineerId { get; set; } public InventoryEngineer Engineer { get; set; } } }
Adicione mais um ficheiro, denominado InventoryEngineer.cs, à pasta Modelos, com o seguinte código. A classe InventoryEngineer regista os engenheiros que fizeram as reservas específicas.
using System.ComponentModel.DataAnnotations; using System.Collections.Generic; namespace FieldEngineerApi.Models { public class InventoryEngineer { [Key] public string Id { get; set; } [Required] public string Name { get; set; } public string ContactNumber { get; set; } public List<Reservation> Reservations { get; set; } } }
Abra o ficheiro InventoryContext.cs na pasta Modelos e adicione as seguintes instruções à classe InventárioContext.
public class InventoryContext : DbContext { public InventoryContext(DbContextOptions\<InventoryContext\> options) : base(options) { } public DbSet<BoilerPart> BoilerParts { get; set; } public DbSet<InventoryEngineer> Engineers { get; set; } public DbSet<Order> Orders { get; set; } public DbSet<Reservation> Reservations { get; set; } }
Na janela do Terminal no Visual Studio Code, execute os seguintes comandos para compilar controladores para lidar com as encomendas e as reservas.
dotnet aspnet-codegenerator controller ^ -name OrdersController -async -api ^ -m Order ^ -dc InventoryContext -outDir Controllers dotnet aspnet-codegenerator controller ^ -name ReservationsController -async -api ^ -m Reservation ^ -dc InventoryContext -outDir Controllers
Abra o ficheiro BoilerPartController.cs na pasta Controladores e adicione o seguinte método GetTotalReservations à classe BoilerPartsController.
public class BoilerPartsController : ControllerBase { private readonly InventoryContext _context; public BoilerPartsController(InventoryContext context) { _context = context; } ... // GET: api/BoilerParts/5/Reserved [HttpGet("{id}/Reserved")] public async Task<ActionResult<object>> GetTotalReservations(long id) { var reservations = await _context .Reservations .Where(r => r.BoilerPartId == id) .ToListAsync(); int totalReservations = 0; foreach(Reservation reservation in reservations) { totalReservations += reservation.NumberToReserve; } return new {id, totalReservations}; } ... }
Edite o ficheiro OrdersController.cs e modifique o método PostOrder na classe OrdersController, tal como é mostrado pelo seguinte.
[HttpPost] public async Task<ActionResult<Order>> PostOrder(long boilerPartId, int quantity) { var part = await _context.BoilerParts.FindAsync(boilerPartId); Order order = new Order { BoilerPartId = boilerPartId, Quantity = quantity, OrderedDateTime = DateTime.Now, TotalPrice = quantity * part.Price }; _context.Orders.Add(order); await _context.SaveChangesAsync(); return CreatedAtAction("GetOrder", new { id = order.Id }, order); }
Edite o ficheiro ReservationsController.cs. Modifique o método PostReservation na classe ReservationsController, da seguinte forma.
[HttpPost] public async Task<ActionResult<Reservation>> PostReservation(long boilerPartId, string engineerId, int quantityToReserve) { Reservation reservation = new Reservation { BoilerPartId = boilerPartId, EngineerId = engineerId, NumberToReserve = quantityToReserve }; _context.Reservations.Add(reservation); await _context.SaveChangesAsync(); return CreatedAtAction("GetReservation", new { id = reservation.Id }, reservation); }
Na janela do Terminal, execute os seguintes comandos para compilar e publicar a API Web pronta para implementação.
dotnet build dotnet publish -c Release -o ./publish
No Visual Studio Code, clique com o botão direito do rato na pasta publicar e, em seguida, selecione Implementar na Aplicação Web.
Preeti pode agora atualizar o serviço Gestão de API utilizado pela aplicação VanArsdel para refletir a API Web atualizada. Esta é uma alteração não interruptiva; as operações existentes continuarão a funcionar, em que a diferença são os novos controladores e as operações para fazer reservas e encomendas. Preeti executa as seguintes tarefas:
Nota
Preeti poderia ter optado por eliminar a API Field Engineer existente e substituí-la por uma nova versão, mas essa abordagem corre o risco de interromper quaisquer aplicações existentes que possam estar atualmente a utilizar a API. É uma melhor pratica deixar a API existente no seu lugar e adicionar as modificações como uma revisão.
No portal do Azure, vá para o serviço Gestão de API.
Na página Serviço de Gestão de API, no painel esquerdo, em APIs, selecione APIs.
Selecione a API Field Engineer, selecione o menu de reticências e, em seguida, selecione Adicionar revisão.
Na caixa de diálogo Criar uma nova revisão da API Field Engineer, introduza a descrição Foram adicionadas as operações GET e POST para encomendas e reservas de peças e selecione Criar.
Na página REVISÃO 2, selecione Estruturar.
Na página Estrutura, selecione Adicionar operação. No painel FrontEnd, defina as seguintes propriedades e selecione Guardar. Esta operação é utilizada para obter o número de itens reservados para uma determinada peça de caldeira:
- Nome a apresentar: api/BoilerParts/{id}/Reserved
- Nome: api-boilerparts-id-reserved
- URL: GET api/BoilerParts/{id}/Reserved
No separador Teste para a nova operação, defina o parâmetro id para um número de peça válido (o exemplo na imagem utiliza a peça 1) e, em seguida, selecione Enviar.
Verifique se o teste foi concluído com êxito. A operação deverá ser concluída com uma resposta HTTP 200 e um corpo que mostra o número de reservas para o produto.
Na página Estrutura, selecione Adicionar operação. No painel FrontEnd, defina as seguintes propriedades (esta operação define os pedidos POST para criar novas encomendas):
- Nome a apresentar: api/Orders - POST
- Nome: api-orders-post
- URL: POST api/Orders
No separador Consulta, selecione + Adicionar parâmetro, adicione os seguintes parâmetros e, em seguida, selecione Guardar:
- Nome: boilerPartId, Descrição : ID da Peça de Caldeira, Tipo: long
- Nome: quantity, Descrição : Quantidade, Tipo: integer
Selecione Adicionar operação novamente no painel FrontEnd e defina as seguintes propriedades (esta operação define os pedidos POST para criar novas reservas):
- Nome a apresentar: api/Reservations - POST
- Nome: api-reservations-post
- URL: POST api/Reservations
No separador Consulta, adicione os seguintes parâmetros e, em seguida, selecione Guardar:
- Nome: boilerPartId, Descrição: ID da Peça de Caldeira, Tipo: long
- Nome: engineerId, Descrição: ID do Engenheiro, Tipo: string
- Nome: quantityToReserve, Descrição: Quantidade a reservar, Tipo: integer
No separador Revisões, selecione a nova versão. No menu de reticências para esta versão, selecione Tornar atual.
Na caixa de diálogo Tornar a revisão atual, selecione Guardar.
Abra outra página no seu browser e vá para o URL https://<APIM name>.azure-api.net/api/boilerparts/1/reserved, em que <APIM name> é o nome do seu serviço da API. Verifique se obtém uma resposta semelhante à seguinte.
{"id":1,"totalReservations":5}
A API Web atualizada está agora disponível. Em teoria, Kiana poderia criar um novo conector personalizado para a API Web atualizada e adicioná-lo à aplicação. A aplicação poderia então implementar a sua própria lógica para determinar quantos itens do produto especificado estão atualmente em stock, quantos estão reservados, comparar os resultados com o número de itens necessários, fazer uma encomenda de mais stock, se for necessário, ou reservar itens do stock existente. No entanto, este tipo de lógica é melhor implementado numa aplicação lógica do Azure. O Power Apps pode chamar a aplicação lógica através de um conector personalizado quando um técnico deseja reservar ou encomendar uma peça.
Para criar a aplicação lógica, Kiana utiliza os seguintes passos:
Nota
Para manter as coisas simples, a aplicação lógica criada neste exemplo é não transacional. É possível que, entre verificar a disponibilidade de uma peça e fazer uma reserva, um utilizador simultâneo possa fazer uma reserva em conflito. Poderá implementar semântica transacional ao substituir parte da lógica nesta aplicação lógica por um procedimento armazenado na base de dados InventoryDB.
No Portal do Azure, na página Home page, selecione + Criar um recurso.
Na caixa de texto Pesquisar no marketplace, introduza Aplicação Lógica e selecione Enter.
Na página Aplicação Lógica, selecione Criar.
Na página Criar uma aplicação lógica, introduza os seguintes valores e selecione Rever + criar:
- Subscrição: selecione a sua subscrição do Azure
- Grupo de recursos: webapi_rg
- Nome da Aplicação Lógica: FieldEngineerPartsOrdering
- Região: Selecione a mesma localização que utilizou para a API Web
- Associar-ao ambiente de serviço de integração: deixar em branco
- Ativar a análise de registos: deixar em branco
Na página de verificação, selecione Criar e aguarde enquanto a aplicação lógica é implementada.
Quando a implementação for concluída, selecione Ir para recurso.
Na página Logic Apps Designer, desloque-se para a secção Modelos e, em seguida, selecione Aplicação Lógica em Branco.
No separador Tudo , na caixa de texto Procurar conectores e acionadores , selecione Pedido.
No separador Acionadores, selecione Quando um pedido de HTTP é recebido.
Na caixa Esquema JSON do Corpo do Pedido, introduza o seguinte esquema e selecione + Novo passo.
{ "type": "object", "properties": { "boilerPartId": { "type": "integer" }, "numberToReserve": { "type": "integer" }, "engineerId": { "type": "string" } } }
Este esquema define o conteúdo do pedido HTTP que a aplicação lógica está à espera. O corpo do pedido é composto pelo ID de uma peça de caldeira, o número de itens a reservar e o ID do engenheiro a fazer o pedido. A aplicação enviará este pedido quando um engenheiro quiser reservar uma peça.
Na caixa Escolher uma operação, selecione Tudo e selecione HTTP.
A aplicação lógica irá chamar a operação BoilerParts{id} da API Web para obter informações sobre a peça de caldeira fornecida pelo pedido da parte da aplicação.
No painel Ações, selecione a ação HTTP.
Na caixa de ação HTTP, no menu de reticências, selecione Mudar Nome e altere o nome da ação para CheckBoilerPart.
Defina as propriedades da ação HTTP da seguinte forma e, em seguida, selecione + Novo Passo:
- Método: GET
- URI: https://<APIM name>.azure-api.net/api/boilerparts/, where <APIM name> é o nome do serviço de Gestão de API. Na caixa Conteúdo dinâmico para este URI, no separador Conteúdo Dinâmico, selecione boilerPartId
Na caixa Escolher uma operação, na caixa Pesquisar conectores e ações, introduza Analisar JSON e selecione a ação Analisar JSON.
Através do menu de reticências para a ação Analisar JSON, mude o nome da ação para ParseBoilerPart.
Na caixa Conteúdo para a ação ParseBoilerPart, na caixa Conteúdo Dinâmico, selecione Corpo. Na caixa Esquema, introduza o seguinte esquema JSON e selecione + Novo passo.
{ "type": "object", "properties": { "id": { "type": "integer" }, "name": { "type": "string" }, "categoryId": { "type": "string" }, "price": { "type": "number" }, "overview": { "type": "string" }, "numberInStock": { "type": "integer" }, "imageUrl": { "type": "string" }, } }
Esta ação analisa a mensagem de resposta devolvida pelo pedido getBoilerParts/{id}. A resposta contém os detalhes da peça de caldeira, incluindo o número atualmente em stock.
Na caixa Escolher uma operação para o novo passo, selecione o conector HTTP.
No separador Ações, selecione a ação HTTP.
Através do menu de reticências para a operação, mude o nome da operação para CheckReservations.
Defina as seguintes propriedades para esta operação e, em seguida, selecione + Novo passo:
- Método: GET
- URI: https://<APIM name>.azure-api.net/api/boilerparts/. Como anteriormente, na caixa Conteúdo dinâmico para este URI, no separador Conteúdo Dinâmico, selecione boilerPartId. No campo URI, anexe o texto /reserved após o marcador de posição boilerPartId
Na caixa Escolher uma operação para a nova ação, na caixa Pesquisar conectores e ações, introduza Analisar JSON e selecione a ação Analisar JSON.
Mude o nome da operação para ParseReservations.
Defina a propriedade Conteúdo como Corpo.
Introduza o seguinte esquema e selecione + Novo passo.
{ "type": "object", "properties": { "id": { "type": "integer" }, "totalReservations": { "type": "integer" } } }
Na caixa Escolher uma operação para a nova ação, na caixa Pesquisar conectores e ações, introduza Condição e selecione a ação Controlo de Condição.
Mude o nome da operação para CompareStock.
Selecione a caixa Escolher um valor. Na caixa Adicionar conteúdo dinâmico, no separador Expressão, introduza a seguinte expressão e, em seguida, selecione OK.
add(body('ParseReservations')?['totalReservations'], triggerBody()?['numberToReserve'])
Esta expressão calcula a soma do número de itens da peça de caldeira especificada que estão atualmente reservados e o número solicitado pelo engenheiro.
Na caixa de lista pendente da condição, selecione é maior que.
Na restante caixa Escolher um valor, na caixa Conteúdo dinâmico, no separador Conteúdo dinâmico, em ParseBoilerPart, selecione numberInStock.
Se o número de itens necessário somado ao número reservado for maior que o número em stock, a aplicação precisa de fazer uma encomenda para repor o inventário. No ramo Verdadeiro da ação CompareStock, selecione Adicionar uma ação.
No separador Tudo para a nova operação, selecione HTTP e, em seguida, selecione a ação HTTP.
Mude o nome da operação para PostOrder.
Defina as seguintes propriedades para a operação PostOrder:
- Método: POST
- URI: https://<APIM name>.azure-api.net/api/orders
- Na tabela Consultas, na primeira fila, introduza a chave boilerPartId. Para o valor na caixa Adicionar conteúdo dinâmico, no separador Conteúdo dinâmico, selecione boilerPartId
- Na segunda linha da tabela Consultas, introduza a chave quantidade. No campo Valor, introduza 50.
A aplicação lógica encomendará automaticamente 50 itens da peça especificada quando o stock estiver a esgotar-se.
Nota
A aplicação lógica pressupõe que o engenheiro não tentará reservar mais de 50 itens de uma peça especificada num único pedido!
Deixe o ramo Falso da ação CompareStock vazio.
Abaixo da ação CompareStock, selecione + Novo passo.
No separador Tudo para a nova operação, selecione HTTP e, em seguida, selecione a ação HTTP.
Mude o nome da operação para PostReservation.
Defina as seguintes propriedades para a operação PostReservation:
- Método: POST
- URI: https://<APIM name>.azure-api.net/api/reservations
- Na tabela Consultas, na primeira fila, introduza a chave boilerPartId. Para o valor na caixa Adicionar conteúdo dinâmico, no separador Conteúdo dinâmico, selecione boilerPartId.
- Na segunda linha, introduza a chave engineerId. Para o valor na caixa Adicionar conteúdo dinâmico, no separador Conteúdo dinâmico, selecione engineerId
- Na terceira linha, introduza a chave quantityToReserve. Para o valor na caixa Adicionar conteúdo dinâmico, no separador Conteúdo dinâmico, selecione numberToReserve
Selecione + Novo passo. Na caixa Escolher uma operação, procure e selecione a ação Resposta.
Defina as seguintes propriedades para a ação Resposta:
- Código de Estado: 200
- Cabeçalhos: Chave - content-type, Valor - application/json
- Corpo: na caixa Conteúdo dinâmico, selecione o elemento Corpo a partir do pedido PostReservation. Este é o corpo devolvido quando a reserva é feita.
Na parte superior esquerda da página Logic Apps Designer, selecione Guardar. Verifique se a aplicação lógica pode ser guardada sem erros.
Para criar o conector personalizado que o Power Apps pode usar para acionar a aplicação lógica, Kiana executa os seguintes passos ainda no portal do Azure:
Na página Descrição Geral para a aplicação lógica, selecione Exportar.
No painel Exportar para Power Apps, atribua ao conector o nome PartsOrderingConnector, selecione o seu ambiente do Power Apps e selecione OK.
Inicie sessão no Power Apps.
No seu ambiente, em Dados, selecione Conectores Personalizados e verifique se PartsOrderingConnector é listado.
Maria pode agora modificar a aplicação VanArsdel para permitir a um técnico encomendar peças enquanto frequenta um site de clientes. Maria adiciona um botão Encomendar ao ecrã PartDetails, da seguinte forma:
Inicie sessão no Power Apps (se ainda não tiver sessão iniciada).
Em Aplicações, selecione a aplicação VanArsdelApp. No menu de reticências para a aplicação, selecione Editar.
No painel Dados, selecione Adicionar dados, procure o conector PartsOrderingConnector e adicione uma nova ligação através desse conector.
No painel Vista de árvore, expanda o ecrã PartDetails e, em seguida, expanda o formulário DetailForm1.
No painel Propriedades à direita, selecione Editar campos. No painel Campos, no menu de reticências, selecione Adicionar um cartão personalizado.
No painel Vista de árvore, mude o nome do novo cartão de DataCard1 para ReserveCard. Na janela Estrutura, redimensione o cartão para ocupar a parte inferior do ecrã, sob o controlo Image_DataCard1.
No menu Inserir, a partir do submenu Input, adicione um controlo Introdução de texto, um controlo Botão e um controlo Etiqueta ao controlo ReserveCard.
Redimensione e posicione os controlos para estarem adjacentes, com o controlo Botão à direita do controlo Introdução de texto e a Etiqueta sob o controlo Botão.
No painel Propriedades para o controlo Introdução de texto, limpe a propriedade Default.
No painel Propriedades para o controlo Botão, defina a propriedade Text como Reservar.
Mude o nome do controlo Introdução de texto para NumberToReserve, mude o nome do controlo Botão para Reservar e mude o nome do controlo Etiqueta como Mensagem.
No painel Propriedades para o controlo Mensagem, defina a propriedade Text como Peças Reservadas e defina a propriedade Visible como MessageIsVisible.
Nota
MessageIsVisible é uma variável que irá inicializar como false quando o ecrã for apresentado, mas será alterado para true se o utilizador selecionar o botão Reservar.
Defina a propriedade OnSelect para o controlo Botão Reservar para a seguinte fórmula.
FieldEngineerPartsOrdering.manualinvoke({boilerPartId:ThisItem.id, engineerId:"ab9f4790-05f2-4cc3-9f01-8dfa7d848179", numberToReserve:NumberToReserve.Text}); Set(MessageIsVisible, true);
Nota
Esta fórmula utiliza um ID de engenheiro hard-coded para representar o técnico que está atualmente a executar a aplicação. O Capítulo 8 descreve como obter o ID para o utilizador com sessão iniciada.
Além disso, a aplicação não executa qualquer verificação de erros; assume que o pedido de reserva de peças é sempre bem-sucedido. Para mais informações sobre o tratamento de erros, vá para Função de erros no Power Apps.
Defina a propriedade OnVisible para o ecrã PartDetails como Set(MessageIsVisible, false).
Para testar a aplicação, faça o seguinte:
No painel Vista de árvore, selecione o ecrã Home page.
Selecione F5 para pré-visualizar a aplicação.
No ecrã Home page, selecione Peças.
No ecrã de procura, selecione qualquer peça.
No ecrã Detalhes das Peças, desloque-se para baixo para a secção de reservas, introduza um valor inteiro positivo e, em seguida, selecione Reservar. Verifique se a mensagem Peças reservadas aparece.
Feche a janela de pré-visualização e regresse ao Power Apps Studio.
No Portal do Azure, vá para a página da Base de Dados SQL InventoryDB.
Selecione o Editor do Power Query e inicie sessão como sqladmin com a sua palavra-passe.
No painel Consulta 1, introduza a seguinte consulta e, em seguida, selecione Executar. Verifique se a reserva que fez na aplicação VanArsdel aparece.
SELECT * FROM [dbo].[Reservations]