共用方式為


第 7 章:為應用程式新增功能

Kiana 和 Maria 很高興向現場技術員 Caleb 展示庫存管理應用程式。 Caleb 喜歡它,但建議添加一些額外的用戶界面功能以使其更易於使用。 具體來說,Caleb 希望能夠:

  • 新增在鍋爐或空調裝置上完成的工作相片,並將其新增至 「編輯約會 」畫面上的約會詳細資料中。 該圖像可以作為所進行維修的書面證據。 [ 編輯約會] 畫面目前可讓使用者將影像新增至約會,但不會儲存影像,因為此功能尚未完全實作。 之所以會省略,是因為Kiana和Preeti需要確定儲存影像資料的最佳位置。 Caleb 希望盡快添加此功能。

  • 檢視客戶的完整預約歷史記錄,以追蹤請求的維修,並監控可能需要重複呼叫技術人員的任何持續問題。

  • 零件詳細資料 畫面訂購零件。

此外, 「零件詳細資料」 畫面上的影像控制項會顯示儲存在指定 URL 中的影像。 目前,資料中的URL只是佔位符。 就像約會畫面的照片一樣,Kiana 和 Preeti 需要確定儲存影像的最佳位置,以便應用程式可以使用這些影像。

將相片新增至約會

照片需要存儲在應用程序可訪問的位置。 基於效能和安全性理由,Preeti 不希望將相片儲存在 OneDrive 或 Azure SQL 資料庫中。 相反地,他們決定使用 Azure Blob 儲存體。 Blob 儲存體已針對保存大型二進位物件進行了優化,而且健全,並具有內建安全性。 Power Apps 有一個連接器,允許存取 Blob 儲存體。 Maria 建議添加一個新的拍照屏幕,改善 Caleb 的用戶體驗。

其他資訊: Azure Blob 儲存體

Preeti 會遵循下列步驟,從 Azure 入口網站建立 Blob 儲存體帳戶:

  1. Azure 入口網站的首 上,選取 [+ 建立資源]。 在搜尋服務商場方塊中,輸入儲存體帳戶,然後選取輸入

    Azure Marketplace 搜尋。

  2. 在 [儲存體帳戶] 頁面上,選取 [建立]。

  3. 在 [ 建立儲存體帳戶 ] 頁面上,輸入下列詳細資料,然後選取 [ 檢閱 + 建立]:

    • 訂閱:選擇您的訂閱
    • 資源群組: webapi_rg
    • 儲存體帳戶名稱:提供全域唯一的名稱,並記下以供日後使用
    • 地點:選擇離您最近的位置
    • 性能: 標準
    • 帳戶種類: BlobStorage
    • 複寫: RA-GRS

    建立 Azure 儲存體帳戶。

  4. 在驗證頁面上,選取 [ 建立 ],然後等候佈建儲存體帳戶。

  5. 移至新儲存體帳戶的頁面。

  6. 在 [概觀] 頁面上,選取 [容器]。

    儲存體帳戶概觀頁面。

  7. [容器] 頁面上,選取 [+ 容器]。 建立名為 photos 的新容器,然後選取 [建立]。公用存取層級 變更為 Blob

    建立「相片」容器。

  8. 返回儲存體帳戶的 [概觀] 頁面,在 [設定] 底下,選取 [存取金鑰]。[存取金鑰 ] 頁面上,選取 [ 顯示金鑰]。 記下 key1 的索引鍵值。

    儲存體帳戶存取金鑰。

Preeti 會將儲存體帳戶名稱和金鑰提供給 Kiana,Kiana 會使用此資訊,遵循下列步驟來建立應用程式的自訂連接器:

  1. 登入 Power Apps

  2. 在左窗格中,展開資料,然後選取連線。 應該列出應用程式使用的現有連線。 選取 + 新增連線

    Power Apps 連線頁面。

  3. 在 [新增連線] 頁面上,向下捲動,選取 [連線],選取 [Azure Blob 儲存體],然後選取 [建立]。

    選取 [Azure Blob 儲存體連接器]。

  4. [Azure Blob 儲存體] 對話方塊中,輸入 Preeti 提供的儲存體帳戶名稱和存取金鑰,然後選取 [建立]。

    輸入儲存體認證。

  5. 等待建立新連線。 它應該出現在連接列表中。

Maria 可以使用與應用程式中 Blob 儲存體的連線來儲存和擷取相片影像。 Maria 的首要任務是按照以下步驟將連線新增至應用程式:

  1. 開啟 VanArsdelApp 應用程式以在 Power Apps Studio 中進行編輯。

  2. 在 [ 資料 ] 窗格中,選取 [ 新增資料],搜尋 Azure Blob 儲存體 連接器,然後選取連接器。

    搜尋 Blob 儲存體連接器。

  3. [Azure Blob 儲存體 ] 對話方塊中,選取 Azure Blob 儲存體 連接器,以將它新增至您的應用程式。

    新增 Blob 儲存體連線。

Maria 的下一個任務是添加一個屏幕,使技術人員或工程師能夠保存照片。 Maria 決定新增一個帶有 Picture 控制項的新螢幕。 當應用程式在行動裝置上執行時,此控制項可以與相機整合,讓技術人員能夠拍照。 在其他裝置上,此控制項會提示使用者改為上傳影像檔案。 Maria 會依照下列步驟,從 EditAppointment 畫面新增此新畫面的連結:

  1. [插入] 功能表上,選取 [ 新增畫面],然後選取 [可捲動] 範本。

    可捲動範本中的新畫面。

  2. [樹狀檢視] 窗格中,選取新畫面,並將其重新命名為 TakePhoto

  3. 將此畫面上 LblAppNameX 控制項的 Text 屬性變更為 拍攝相片

  4. 從畫面中刪除 CanvasX 控制項。

  5. [插入] 功能表的 [ 媒體 ] 下拉式清單中,選取 [ 新增圖片 ] 以建立新的圖片控制項。

    新增 [圖片] 控制項。

    備註

    圖片控制項實際上是一個複合自訂元件,可讓使用者將圖片新增至螢幕並顯示結果。

  6. 調整圖片控制項的大小並重新置放,以佔用畫面的主體。

  7. [樹狀檢視] 窗格上,選取 [AppointmentDetails] 畫面上的 IconBackarrowX 控制項,然後選取 [複製]。

    複製 [返回箭頭] 控制項。

  8. [樹狀檢視] 功能表上,以滑鼠右鍵按一下 [TakePhoto ] 畫面,然後選取 [ 貼上]。 IconBackArrowX 控制項將會新增至畫面。

    將 [返回箭頭] 控制項貼到 [TakePhoto] 畫面中。

  9. IconBackArrowX 控制項移至標頭列的左上方。

  10. [樹狀檢視] 窗格上,選取 [TakePhoto] 畫面上的 IconBackArrowX 控制項。 在右窗格的 進階 索引標籤上,將 OnSelect 動作屬性修改為 導航(EditAppointment, ScreenTransition.None)

  11. 在標頭列的右上角新增 [儲存 ] 圖示控制項。 將此控制項的 Visible 屬性設定為 If(IsBlank(AddMediaButton1.Media), false, true)。

    如果使用者尚未選取影像,此設定會讓 [儲存] 圖示不可見。

    新增 [儲存] 圖示控制項。

  12. [儲存圖示] 控制項的 OnSelect 動作屬性中的公式變更為下列內容。

    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);
    

    <儲存體帳戶名稱>替換為 Preeti 所建立的 Azure 儲存體帳戶名稱。

    此程式碼會將影像上傳至 Blob 儲存體中的 相片 容器。 每個圖像都有一個唯一的文件名。 Patch 函式會使用 Blob 儲存體中影像的 URL 更新約會記錄中的 imageUrl 屬性。

  13. [樹狀結構檢視 ] 窗格中,展開 AddMediaWithImageX 控制項。 修改 UploadedImageX 控制項的 Image 屬性,並將它設定為 AppointmentImage

    AppointmentImage 是一個變數,它將被用來儲存由使用者上傳的圖像或拍攝照片的結果。 您稍後將在 EditAppointment 畫面中初始化此變數。

  14. [樹狀結構檢視 ] 窗格中,選取 AddMediaButtonX 控制項。 將此控制項的 UseMobileCamera 屬性設定為 true。 將控制項的 OnChange 動作屬性設定為下列項目。

    Set(AppointmentImage, AddMediaButton1.Media)
    

    此公式會變更 AppointmentImage 變數以參考新影像。 UploadedImageX 控制項會顯示此影像。

  15. [樹狀檢視 ] 窗格中,選取 [編輯約會 ] 畫面。

  16. 展開 EditFormX 控制項。 在 Image_DataCardX 控制項下,移除 AddPictureX 控制項。

    移除 AddPicture 控制項。

  17. 選取 [影像X] 控制項。 變更下列屬性:

    • 圖片: Parent.Default
    • X: 30
    • Y: DataCardKeyX。Y + DataCardKeyX。高度 + 150 (其中 DataCardKeyX 是包含 影像X 控制項的資料卡)
    • 寬度: Parent.Width - 60
    • 高度: 400

    備註

    影像控制項會下拉至螢幕底部下方,但會自動新增捲軸以檢視影像。

  18. 在資料卡中 新增相機圖示 ,然後將其放置在 影像 標籤和 ImageX 控制項之間。 將控制項的名稱變更為 CameraIcon

    備註

    請確定您選取 [相機圖示] 控制項, 而不是 [相機媒體] 控制項。

    新增相機圖示。

  19. CameraIcon 控制項的 OnSelect 動作屬性設定為下列項目。

    Set(AppointmentImage, SampleImage);
    
    Navigate(TakePhoto, ScreenTransition.None);
    

    當使用者選取此圖示時,他們會移至 [TakePhoto ] 畫面,可在其中拍照或上傳影像。 顯示的初始影像將是預設範例影像。

若要測試應用程式,請執行下列動作:

  1. 樹狀檢視 窗格中,選取 主畫面

  2. 選取 F5 以預覽應用程式。

  3. 主畫面上,選取約會。

  4. 在瀏覽畫面中,選取任何約會。

  5. 在約會的詳細資料畫面上,選取螢幕標題中的編輯圖示。

  6. 在編輯畫面上,選取影像的 相機 圖示。

  7. 確認 [ 拍照 ] 畫面出現。

  8. 選取 [ 變更圖片 ] 並上傳您選擇的圖片 (如果您在行動裝置上執行應用程式,請拍照)。

  9. 選取 [儲存]。 確認影像出現在詳細資料頁面上,然後選取勾號圖示,將變更儲存回資料庫。

  10. 關閉預覽視窗並返回 Power Apps Studio。

顯示零件的影像

在確定 Blob 存儲是保存與約會相關的圖片的理想位置後,Preeti 和 Kiana 決定他們應該使用相同的方法來存儲部件的圖像。 這種方法的一個主要優點是它不需要對應用程式進行任何修改。 應用程式會重複使用相同的儲存體帳戶和相同的連線。 作為單獨的遷移練習,他們可以執行以下操作:

  1. 建立新的 Blob 儲存體容器。

  2. 將零件影像上傳至此容器。

  3. InventoryDB 資料庫中「零件」表格中的 ImageUrl 參照變更為每個影像的 URL。

應用程式會自動挑選每個零件影像的新 URL,而 [零件詳細資料] 畫面上的 [影像] 控制項會顯示影像。

追蹤客戶的預約紀錄

Maria 認為,能夠快速檢視客戶先前技術人員造訪的所有歷史記錄可以透過建立自訂元件新增至應用程式。 瑪麗亞與迦勒合作,確定他們想要看到的信息,勾勒出一個簡單的設計,包括每次訪問的筆記和日期。

客戶約會記錄資料。

查看數據,Maria 認為圖庫控件是在屏幕上顯示表格數據的最佳方式。

Maria 會建立自訂元件,如下所示:

  1. 使用 Power Apps Studio,在 樹狀檢視 窗格上,選取 元件,然後選取 + 新增元件

    建立新元件。

    會建立名為 Component1 的新空白元件。 將元件重新命名為 DateHistoryComponent

    重新命名元件。

  2. [插入] 功能表上,選取 [圖庫],然後選擇 [空白彈性高度] 圖庫範本。

    新增圖庫控制項。

  3. 移動圖庫控制項並調整其大小以填滿自訂元件。

  4. 插入窗格中選取新增項目,然後選取文字標籤

    將 文字 標籤新增至元件。

  5. [樹狀結構檢視] 窗格中,將標籤控制項重新命名為 NotesLabel。 將 Overflow 屬性設定為 Overflow.Scroll。 此設定可讓控制項顯示數行文字,並允許使用者捲動它。 設定下列屬性,以便您可以定位控制項並調整大小:

    • 線高: 2
    • X: 28
    • Y: 18
    • 寬度: 574
    • 身高: 140
  6. 將第二個文字標籤新增至控制項。 將此控制項重新命名為 DateLabel,並設定下列屬性:

    • 線高: 2
    • X: 28
    • Y: 174
    • 寬度: 574
    • 身高: 70
  7. 若要查看控制項插入應用程式並以其主題顯示時的外觀,請在 [樹狀檢視] 窗格上選取 [DateHistoryComponent]。 在右窗格的 進 索引標籤上,選取 填滿 欄位,並將色彩變更為 RGBA(0, 0, 0, 1)。

    檢視元件。

  8. [插入 ] 窗格中,展開 [圖形],並將 [矩形] 控制項新增至自訂元件。 設定此控制項的下列屬性:

    • X: 0
    • Y: 273
    • 寬度: Parent.Width
    • 高度: 2

    此控制項用於圖庫中顯示的記錄之間的分隔。

    新增 Rectangle 控制項。

Maria 熟悉使用 Power Apps 將控制項新增至螢幕和建置應用程式。 然而,可重複使用的組件的工作方式並不完全相同。 Kiana 向 Maria 描述,為了能夠在自訂元件中使用資料,必須新增一些額外的自訂輸入屬性。 Kiana 也解釋說,Maria 需要為這些屬性提供範例數據,以引用元件中控制項中的資料欄位,如下所示:

  1. [樹狀檢視] 窗格中,選取 [DateHistoryComponent]。 在右窗格的 屬性 索引標籤上,選取 新增自訂屬性

    新的自訂屬性。

  2. [新增自訂屬性 ] 對話方塊中,指定下列值,然後選取 [建立]

    • 顯示名稱: 數據
    • 名稱: 數據
    • 描述: 客戶的約會表格,顯示附註和日期
    • 屬性類型: 輸入
    • 資料類型: 表格
    • 當值變更時提高 OnReset:保留空白

    新的自訂屬性屬性。

  3. 若要變更控制項所顯示的範例資料,請選取新的 [資料 ] 自訂屬性。 在公式欄位中,輸入 Table({Notes:「範例備註欄位文字」,'Appointment Date':Text(Today())})。

    變更範例資料。

  4. [樹狀檢視] 窗格中,選取 DateHistoryComponent 中的 [資源庫X] 控制項,並將它重新命名為 AppointmentHistory

  5. 在右窗格的 [進階] 索引標籤上,將 AppointmentHistory 資源庫控制項的 Items 屬性設定為 Parents.Data

    更新畫廊控制項的 Items 屬性。

  6. 選取 NotesLabel 控制項。 在 [ 進階 ] 索引標籤的右窗格中,將 [文字] 屬性變更為 ThisItem.Notes, 並將 [大小] 屬性變更為 20

    備註

    Size 屬性會指定控制項所顯示文字的字型大小。

  7. 選取 DateLabel 控制項,將 Text 屬性變更為 ThisItem.'Appointment Date' ,並將 Size 屬性變更為 20。 自訂元件中的欄位應該顯示範例資料。

    具有範例資料的自訂元件。

自訂元件已完成。 Maria 使用此元件建立新畫面來顯示客戶的約會歷程記錄,如下所示:

  1. 樹狀檢視 窗格中,選取 螢幕 索引標籤。

  2. 展開 [BrowseAppointments ] 畫面,展開 [BrowseAppointmentsGallery ] 控制項,然後選取 Body1_1 控制項。 在 [插入] 功能表上,選取 [ 圖示],然後選取 [詳細資料清單] 圖示。

    新增詳細資料清單圖示。

  3. 將圖示控制項的名稱變更為 ViewAppointments

  4. [樹狀檢視] 功能表上,選取 [BrowseAppointmentsGallery ] 控制項。 在右窗格的 [ 進階 ] 索引標籤上,將 TemplateSize 屬性變更為 220。 增加此屬性會擴大圖庫中的可用空間。

  5. ViewAppointments 圖示移至客戶名稱下方的空白區域。

    已修改的約會資料庫。

  6. 選取 ViewAppointments 圖示控制項。 將 OnSelect 動作屬性設定為下列公式。

    ClearCollect(customerAppointmentsCollection, FieldEngineerAPI.getapicustomeridappointments(ThisItem.customerId));
    
    Navigate(AppointmentsHistoryScreen, ScreenTransition.Fade)
    

    此公式會以所選客戶的約會填入名為 customerAppointmentsCollection 的集合,然後移至 AppointmentHistoryScreen 以顯示它們。 您將在下列步驟中建立此畫面。

  7. [插入] 功能表上,選取 [ 新增畫面],然後選取 [可捲動] 範本。

    基於可捲動範本的新畫面。

  8. 將新畫面的名稱變更為 AppointmentHistoryScreen

  9. 刪除新增至此畫面的 CanvasX 控制項。

    刪除 Canvas 控制項。

  10. 選取此畫面上的 LblAppNameX 控制項。 在右窗格的 進 索引標籤上,將 Text 屬性變更為下列內容。

    "Appointments History for " &  BrowseAppointmentsGallery.Selected.customer.name
    
  11. 設定 LblAppNameX 控制項的下列屬性,以調整位置和大小:

    • X: 90
    • Y: 0
    • 寬度: 550
    • 身高: 140
  12. 選取 RectQuickActionBarX 控制項,並將 Height 屬性設定為 140

  13. [左] 圖示 控制項新增至標題左側的螢幕標頭。 將此控制項的 OnSelect 動作屬性設定為 Navigate(BrowseAppointments, Transition.None)。

    清空約會歷程記錄畫面。

  14. [插入] 功能表上,選取 [自訂],然後選取 [DateHistoryComponent]。

    新增 DateHistory 元件。

  15. 移動元件並調整其大小,使其佔據標題下方的螢幕主體。

    調整元件大小。

  16. 為此元件設定下列屬性:

    • 資料: customerAppointmentsCollection
    • 約會日期: startDateTime
    • 筆記: 筆記
  17. 儲存應用程式。

若要測試應用程式,請執行下列動作:

  1. 樹狀檢視 窗格中,選取 主畫面

  2. 選取 F5 以預覽應用程式。

  3. 主畫面上,選取約會。

  4. 在瀏覽畫面中,為任何約會選取詳細資料清單圖示。

  5. 確認所選客戶的 約會歷史記錄 畫面出現。

  6. 關閉預覽視窗並返回 Power Apps Studio。

訂購零件

該系統的一個關鍵要求是使技術人員能夠在拜訪客戶時訂購所需的任何零件。 如果零件有庫存,應該可以安排另一次訪問,以便在客戶方便的下一個日期完成維修。 如果零件目前缺貨且必須訂購,技術人員可以告訴客戶。 然後,當 Maria 收到零件已到達倉庫的通知時,Malik 可以安排與客戶的約會。

應用程式的保留部分會使用下圖所示的 InventoryDB 資料庫中的資料表。 「訂單」表格包含有關零件訂單的資訊。 「 保留」 表格會列出技術人員與工程師對零件提出的保留要求。 工程師 表格 提供進行預訂的工程師的姓名和聯絡電話,這使得庫存經理 Maria 在必要時可以輕鬆查詢。

預訂資料模型。

為了支援此功能,Kiana 必須使用提取指定組件保留項目數量的方法來更新 Web API,如下所示:

  1. 在 Visual Studio Code 中開啟 FieldEngineerApi Web API 專案。

  2. 將名為 Order.cs 的檔案新增至 Models 資料夾。 將下列程式碼新增至此檔案。 Orders 類別會追蹤零件訂單的詳細資料。

    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; }
        }
    }
    
  3. 將另一個名為 Reservation.cs 的新檔案新增至 Models 資料夾,並將下列程式碼新增至此檔案。 Reservation 類別包含目前為其他客戶保留的指定零件項目數目的相關資訊。

    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; }
        }
    }
    
  4. 使用下列程式碼,將另一個名為 InventoryEngineer.cs 的檔案新增至 Models 資料夾。 InventoryEngineer 類別會記錄哪些工程師已進行哪些保留。

    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; }
        }
    }
    
  5. 開啟 Models 資料夾中的InventoryContext.cs檔案,並將下列陳述式新增至 InventoryContext 類別。

    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; }
    }
    
  6. 在 Visual Studio Code 的 [終端機] 視窗中,執行下列命令來建置控制器來處理訂單和保留。

    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
    
  7. 開啟 Controllers 資料夾中的BoilerPartController.cs檔案,並將下列 GetTotalReservations 方法新增至 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}; 
        }
        ...
    }
    
  8. 編輯OrdersController.cs檔案,並修改 OrdersController 類別中的 PostOrder 方法,如下所示。

    [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);
    }
    
  9. 編輯 ReservationsController.cs 檔案。 修改 ReservationsController 類別中的 PostReservation 方法,如下所示。

    [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);
    }
    
  10. 在 [終端機] 視窗中,執行下列命令來建置和發佈可供部署的 Web API。

    dotnet build
    dotnet publish -c Release -o ./publish
    
  11. 在 Visual Studio Code 中,以滑鼠右鍵按一下 發佈 資料夾,然後選取 [部署至 Web 應用程式]。

Preeti 現在可以更新 VanArsdel 應用程式所使用的 API 管理 服務,以反映更新的 Web API。 這是非重大變更;現有業務將繼續運作,不同之處在於新的控制者和進行預訂和下訂單的業務。 Preeti 執行下列工作:

備註

Preeti 本可以選擇刪除現有的現場工程師 API 並用新版本替換它,但這種方法可能會破壞當前可能使用該 API 的任何現有應用程序。 最好保留現有的 API,並將修改新增為修訂。

  1. 在 Azure 入口網站中,移至 API 管理 服務。

  2. [API 管理 服務] 頁面的左窗格 [API] 底下,選取 [API]。

  3. 選取 Field Engineer API,選取省略符號功能表,然後選取 [新增修訂]。

    將修訂新增至 Field Engineer API。

  4. 建立現場工程師 API 的新版本修訂對話方塊中,輸入描述新增了零件預留和訂單的 GET 操作及 POST 操作,然後選擇建立

    建立修訂。

  5. REVISION 2 頁面上,選取 設計

    設計修訂。

  6. [設計 ] 頁面上,選取 [新增作業]。 在 [前端 ] 窗格中,設定下列屬性,然後選取 [儲存]。 此作業用於擷取為指定鍋爐零件保留的項目數:

    • 顯示名稱: api/BoilerParts/{id}/Reserved
    • 名稱:api-boilerparts-id-reserved
    • 網址: GETapi/BoilerParts/{id}/Reserved

    新增保留 API 作業。

  7. 在新作業的 [測試 ] 索引標籤上,將 id 參數設定為有效的零件編號 (影像中的範例使用零件 1),然後選取 [傳送]。

    測試 Web API。

  8. 確認測試成功。 操作應該以 HTTP 200 回應成功完成,並且其內文顯示產品預訂數量。

    測試回應。

  9. [設計 ] 頁面上,選取 [新增作業]。 在 [前端] 窗格中,設定下列屬性 (此作業會定義建立新訂單的 POST 要求):

    • 顯示名稱: api/Orders - POST
    • 名稱: api-orders-post
    • 網址: POSTapi/訂單
  10. [查詢] 索引標籤上,選取 [+ 新增參數],新增下列參數,然後選取 [儲存]:

    • 名稱: boilerPartId,描述**:鍋爐零件 ID**,類型: long
    • 名稱: 數量,描述**:數量**,類型: 整數

    將參數新增至 API 管理 查詢作業。

  11. [前端] 窗格上再次選取 [新增作業],然後設定下列屬性 (此作業會定義建立新保留的 POST 要求):

    • 顯示名稱: api/Reservations - POST
    • 名稱: api-reservations-post
    • 網址: POSTapi/Reservations
  12. [查詢] 索引標籤上,新增下列參數,然後選取 [儲存]

    • 名稱: boilerPartId,描述: 鍋爐零件 ID,類型: long
    • 名稱: engineerId,描述: 工程師 ID,類型: 字串
    • 名稱: quantityToReserve,描述: 要保留的數量,類型: 整數
  13. 修訂索引 標籤上,選取新版本。 在此版本的省略符號選單中,選取 設為目前

    設定修訂的目前版本。

  14. [將修訂設為目前] 對話方塊中,選取 [儲存]。

  15. 在網頁瀏覽器中開啟另一個頁面,然後移至 URL https:// <APIM name.azure-api.net/api/boilerparts/1/reserved><其中 APIM 名稱>是 API 服務的名稱。 確認您收到類似下列的回應。

    {"id":1,"totalReservations":5}
    

更新的 Web API 現已推出。 理論上,Kiana 可以為更新的 Web API 創建一個新的自定義連接器,並將其添加到應用程序中。 然後,該應用程序可以實現自己的邏輯,以確定指定產品當前有多少庫存、有多少保留、將結果與所需項目數量進行比較、必要時下訂單以獲取更多庫存,或從現有庫存中保留項目。 不過,這種邏輯在 Azure 邏輯應用程式中實作效果更好。 當技術人員想要保留或訂購零件時,Power Apps 可以透過自訂連接器呼叫邏輯應用程式。

若要建立邏輯應用程式,Kiana 會使用下列步驟:

備註

為了讓事情變得簡單,在此範例中建立的邏輯應用程式是非交易式的。 在檢查零件的可用性與進行預訂之間,並行使用者可能會進行衝突的預訂。 您可以將此邏輯應用程式中的某些邏輯取代為 InventoryDB 資料庫中的預存程序,以實作交易語意。

  1. Azure 入口網站的首 上,選取 [+ 建立資源]。

  2. 在 [ 搜尋市集 ] 方塊中,輸入 [邏輯應用程式],然後選取 [Enter]。

  3. [邏輯應用程式] 頁面上,選取 [建立]。

    建立邏輯應用程式。

  4. 在 [ 建立邏輯應用程式 ] 頁面上,輸入下列值,然後選取 [ 檢閱 + 建立]:

    • 訂用帳戶:選取您的 Azure 訂用帳戶
    • 資源群組: webapi_rg
    • 邏輯應用程式名稱: FieldEngineerPartsOrdering
    • 區域:選取您用於 Web API 的相同位置
    • 與集成服務環境建立關聯:留空
    • 啟用日誌分析:保留空白
  5. 在驗證頁面上,選取 [建立],然後等候部署邏輯應用程式。

  6. 部署完成時,請選取 [移至資源]。

  7. [Logic Apps 設計工具 ] 頁面上,向下捲動至 [範本 ] 區段,然後選取 [空白邏輯應用程式]。

    選取 [空白邏輯應用程式] 範本。

  8. 【全部】 標籤頁的 【搜尋連接器和觸發程式】 文字方塊中,選取 【請求】

    選取 [要求] 觸發器。  

  9. 觸發器 索引標籤上,選取 收到 HTTP 要求時

    收到 HTTP 要求時觸發。

  10. 要求主體 JSON 結構描述方塊中,輸入下列結構描述,然後選取 + 新步驟

    {
        "type": "object",
        "properties": {
            "boilerPartId": {
                "type": "integer"
            },
            "numberToReserve": {
                "type": "integer"
            },
            "engineerId": {
                "type": "string"
            }
        }
    }
    

    邏輯應用程式要求結構描述。

    此結構描述會定義邏輯應用程式預期的 HTTP 要求內容。 請求主體包括鍋爐零件的 ID、要保留的項目數量以及提出請求的工程師的 ID。 當工程師想要保留零件時,該應用程序將發送此請求。

  11. 在 [選擇作業] 方塊中,選取 [全部],然後選取 [HTTP]。

    選取 H HTTP 作業選項。

    邏輯應用程式會呼叫 Web API 的 BoilerParts{id} 作業,以擷取應用程式要求所提供的鍋爐零件相關資訊。

  12. [動作] 窗格中,選取 HTTP 動作。

    選取 HTTP 動作選項。

  13. [HTTP 動作] 方塊的省略符號功能表上,選取 [ 重新命名],並將動作的名稱變更為 CheckBoilerPart

    重新命名 HTTP 動作。

  14. 設定 HTTP 動作的屬性,如下所示,然後選取 [+ 新增步驟]

    • 方法: GET
    • URI:https:// <APIM name.azure-api.net/api/boilerparts/>,其中 <APIM 名稱>是 API 管理 服務的名稱。 在此 URI 的 動態內容 方塊中,在 動態內容 索引標籤上,選取 boilerPartId

    指定 HTTP 動作的動態內容。

  15. 選擇作業方塊中,於搜尋連接器和動作方塊中輸入剖析 JSON,然後選取剖析 JSON動作。

    選擇剖析 JSON 的動作。

  16. 使用剖析 JSON動作的省略號選單將動作重新命名為ParseBoilerPart

  17. ParseBoilerPart 動作的 [內容] 方塊中,在 [動態內容] 方塊中,選取 [內文]。[結構描述] 方塊中,輸入下列 JSON 結構描述,然後選取 [+ 新增步驟]。

    {
        "type": "object",
        "properties": {
            "id": {
                "type": "integer"
            },
            "name": {
                "type": "string"
            },
            "categoryId": {
                "type": "string"
            },
            "price": {
                "type": "number"
            },
            "overview": {
                "type": "string"
            },
            "numberInStock": {
                "type": "integer"
            },
            "imageUrl": {
                "type": "string"
            },
        }
    }
    

    解析 BoilerPart 物件。

    此動作會剖析 getBoilerParts/{id} 要求所傳回的回應訊息。 回應包含鍋爐零件的詳細資料,包括目前庫存的數量。

  18. 在新步驟的 [選擇作業 ] 方塊中,選取 HTTP 連接器。

  19. [動作] 索引標籤上,選取 HTTP 動作。

  20. 使用省略號功能表來執行操作,將作業重新命名為 CheckReservations

  21. 設定此作業的下列屬性,然後選取 [+ 新增步驟]:

    • 方法: GET
    • URI:https://<APIM name>.azure-api.net/api/boilerparts/。 如同先前,在此 URI 的 [動態內容] 方塊中,在 [動態內容] 索引標籤上,選取 boilerPartId。 在 URI 欄位中,將文字 /reserved 附加到 boilerPartId 預留位置之後

    CheckReservations 的步驟。

  22. 在新動作的 [選擇作業 ] 方塊中,在 [搜尋連接器和動作 ] 方塊中,輸入 [剖析 JSON],然後選取 [ 剖析 JSON ] 動作。

  23. 將作業重新命名為 ParseReservations

  24. Content 屬性設定為 Body

  25. 輸入下列結構描述,然後選取 [+ 新增步驟]。

    {
        "type": "object",
        "properties": {
            "id": {
                    "type": "integer"
            },
            "totalReservations": {
                    "type": "integer"
            }
        }
    }
    

    剖析保留資料。

  26. 在新動作的 [選擇作業 ] 方塊中,在 [搜尋連接器和動作 ] 方塊中,輸入 [條件],然後選取 [條件控制 ] 動作。

    選取條件控制項。

  27. 將作業重新命名為 CompareStock

  28. 選取 [ 選擇值 ] 方塊。 在 [新增動態內容 ] 方塊的 [運算式 ] 索引標籤上,輸入下列運算式,然後選取 [ 確定]。

    add(body('ParseReservations')?['totalReservations'], triggerBody()?['numberToReserve'])
    

    此運算式會計算目前預留的指定鍋爐零件的項目數與工程師要求的數的總和。

    CompareStock 條件。

  29. 在條件下拉式清單方塊中,選取 大於

  30. 在剩餘的 選擇值 方塊中,在 動態內容 方塊的 動態內容 索引標籤的 ParseBoilerPart 底下,選取 numberInStock

    將總預訂量與庫存商品數量進行比較。

  31. 如果所需商品數量加上預留數量大於庫存數量,則應用程式需要下訂單來補充庫存。 在 CompareStock 動作的 True 分支中,選取 新增動作

  32. 在新作業的 [ 全部 ] 索引標籤上,選取 [HTTP],然後選取 [HTTP ] 動作。

  33. 將作業重新命名為 PostOrder

  34. 設定 PostOrder 作業的下列屬性:

    • 方式: POST
    • URI: https:// <APIM 名稱>.azure-api.net/api/orders
    • [查詢] 資料表的第一列中,輸入索引鍵 boilerPartId。 針對 [新增動態內容 ] 方塊中的值,在 [動態內容] 索引標籤上,選取 **boilerPartId **
    • [查詢] 資料表的第二列中,輸入索引鍵 數量。 在值欄位中,輸入 50

    張貼訂購更多零件的請求。

    當庫存不足時,邏輯應用程式會自動訂購指定零件的 50 個項目。

    備註

    邏輯應用程式假設工程師實際上不會嘗試在單一要求中保留指定組件的 50 個以上項目!

  35. CompareStock 動作的 False 分支保留空白。

  36. CompareStock 動作下方,選取 + 新增步驟

  37. 在新作業的 [ 全部 ] 索引標籤上,選取 [HTTP],然後選取 [HTTP ] 動作。

  38. 將作業重新命名為 PostReservation

  39. 設定 PostReservation 作業的下列屬性:

    • 方式: POST
    • URI: https:// <APIM 名稱>.azure-api.net/api/reservations
    • [查詢] 資料表的第一列中,輸入索引鍵 boilerPartId。 針對 新增動態內容 方塊中的值,在 動態內容 索引標籤上,選取 boilerPartId
    • 在第二列中,輸入索引鍵 engineerId。 針對 [新增動態內容 ] 方塊中的值,在 [動態內容] 索引標籤上,選取 engineerId
    • 在第三列中,輸入索引鍵 quantityToReserve。 針對 [新增動態內容 ] 方塊中的值,在 [動態內容] 索引標籤上,選取 numberToReserve
  40. 選取 [+ 新增步驟]。 在 [ 選擇作業 ] 方塊中,搜尋並選取 [回應] 動作。

  41. 設定 回應動作 的下列屬性:

    • 狀態代碼: 200
    • 標頭:鍵 - 內容類型,值 - application/json
    • 內文:在動態內容方塊中,從PostReservation請求中選取Body元素。 這是在進行預訂時所傳回的主體。

    邏輯應用程式所傳送的回應訊息。

  42. [Logic Apps 設計工具 ] 頁面的左上角,選取 [ 儲存]。 確認邏輯應用程式可以儲存而不會發生任何錯誤。

若要建立 Power Apps 可用來觸發邏輯應用程式的自訂連接器,Kiana 會在 Azure 入口網站中執行下列步驟:

  1. 在邏輯應用程式的 [概觀] 頁面上,選取 [匯出]。

    匯出邏輯應用程式。

  2. 匯出至 Power Apps 窗格中,將連接器命名為 PartsOrderingConnector,選取您的 Power Apps 環境,然後選取 確定

    將邏輯應用程式匯出至 Power Apps。

  3. 登入 Power Apps

  4. 在您的環境中,在 [資料] 底下,選取 [自訂連接器] ,並確認已列出 PartsOrderingConnector

    Power Apps 自訂連接器。

Maria 現在可以修改 VanArsdel 應用程序,使技術人員能夠在前往客戶現場時訂購零件。 Maria 將 [訂單] 按鈕新增至 [零件詳細資料 ] 畫面,如下所示:

  1. 登入 Power Apps (如果尚未登入)。

  2. [應用程式] 底下,選取 [VanArsdelApp ] 應用程式。 在應用程式的省略符號功能表上,選取 [編輯]。

  3. [資料 ] 窗格中,選取 [ 新增資料],搜尋 PartsOrderingConnector 連接器,然後使用該連接器新增連線。

    將 PartsOrdering 連接器新增至應用程式。

  4. [樹狀檢視 ] 窗格中,展開 [PartDetails ] 畫面,然後展開 [DetailForm1 ] 表單。

  5. 在右側的 屬性 窗格中,選取 編輯欄位。 在欄位窗格的省略符號功能表中,選取新增自訂卡片

    將自訂資料卡控制項新增至應用程式。

  6. [樹狀檢視] 窗格中,將新卡片從 DataCard1 重新命名為 ReserveCard。 在 [設計檢視 ] 視窗中,調整卡片大小,使其佔據螢幕下部,即 Image_DataCard1 控制項下方。

    重新命名資料卡控制項並調整其大小。

  7. [插入] 功能表的 [ 輸入 ] 子功能表中,將 [文字輸入 ] 控制項、 Button 控制項和 [標籤 ] 控制項新增至 ReserveCard 控制項。

  8. 調整控制項的大小並放置控制項,使其相鄰, Button 控制項位於 [文字輸入] 控制項的右側,而 Label 位於 [按鈕 ] 控制項下方。

  9. [文字輸入] 控制項的 [屬性] 窗格上,清除 [預設] 屬性。

  10. Button 控制項的 [屬性] 窗格上,將 [文字] 屬性設定為 [保留]。

    ParttDetails 畫面的版面配置。

  11. [文字輸入 ] 控制項重新命名為 NumberToReserve,將 [按鈕] 控制項重新命名為 Reserve,並將 [標籤] 控制項重新命名為 Message

  12. [訊息] 控制項的 [屬性] 窗格上,將 [文字] 屬性設定為 [保留的零件],並將 [可見] 屬性設定為 [MessageIsVisible]。

    備註

    MessageIsVisible 是顯示畫面時會初始化為 false 的變數,但如果使用者選取 [保留] 按鈕,則會變更為 true

  13. [保留] 按鈕控制項的 OnSelect 屬性設定為下列公式。

    FieldEngineerPartsOrdering.manualinvoke({boilerPartId:ThisItem.id, engineerId:"ab9f4790-05f2-4cc3-9f01-8dfa7d848179", numberToReserve:NumberToReserve.Text});
    
    Set(MessageIsVisible, true);
    

    備註

    此公式使用硬式編碼的工程師識別碼來代表目前執行應用程式的技術人員。 第 8 章說明如何擷取已登入使用者的 ID。

    此外,該應用程序不執行錯誤檢查;它假設保留零件的要求一律成功。 如需有關錯誤處理的詳細資訊,請移至 Power Apps 中的錯誤功能

  14. PartDetails 畫面的 OnVisible 屬性設定為 Set(MessageIsVisible, false)。

若要測試應用程式,請執行下列動作:

  1. 樹狀檢視 窗格中,選取 主畫面

  2. 選取 F5 以預覽應用程式。

  3. 主畫面上,選取零件。

  4. 在瀏覽畫面中,選取任何零件。

  5. [零件詳細資料] 畫面上,向下捲動至保留區段,輸入正整數值,然後選取 [保留]。 確認出現 保留零件 訊息。

    啟用預留功能的零件詳細資料畫面。

  6. 關閉預覽視窗並返回 Power Apps Studio。

  7. 在 Azure 入口網站中,移至 InventoryDB SQL 資料庫的頁面。

  8. 選取 [查詢編輯器],然後使用您的密碼以 sqladmin 身分登入。

  9. [查詢 1] 窗格中,輸入下列查詢,然後選取 [執行]。 確認您在 VanArsdel 應用程式中進行的預訂已顯示。

    SELECT * FROM [dbo].[Reservations]
    

    查詢結果會顯示在 SQL Database 中。