上一節我們完成了頁面 NewRequestScreen 的解析,那個頁面相當于是送出請假申請的第一步,選擇要請的假期的類型。
本節接下來會沿着這個申請,一步步解析相關的頁面。
當點選了假期類型後,所跳轉到的頁面就是下面這個 SelectDatesScreen,讓使用者選擇假期的開始日期和結束日期。
1. 頁面結構
從上圖能看出的是,整個頁面由多種獨立控件組成。從上到下,這個頁面涉及到圖示、标簽、圖檔、幾何形狀、日期拾取器和按鈕六種控件。
2. 控件解析
接下來我們就逐個看這些控件和如何結合在一起運作的。
首先,注意到SelectDatesScreen層面上設定了 OnVisible 屬性:
OnVisible = If(!_editingRequest && !_reviewRequest, Set(_leaveStart,Today());Set(_leaveEnd,Today())); //如果目前既不是編輯之前的申請(!_editingRequest) 也不是檢視之前的申請(!_reviewRequest),就把開始日期和結束日期都設定成當天(相當于是建立一個申請)。
//注意: 本節多次用到這兩個布爾類型的變量 _editingRequest 和 _reviewRequest。
//這兩個變量在之前的HomeScreen裡有做過初始化設定,後續根據申請頁面的狀态不同,還有幾個頁面也對其進行了初始化設定。
2.1 iconBackSelectDates - 左上角的傳回按鈕
OnSelect = Back();Reset(LeaveStartDatePicker);Reset(LeaveEndDatePicker) //傳回上一頁,然後重置兩個日期拾取器
2.2 LabelSelectDatesHeader - 頁面标題
Text = If(_editingRequest, "Edit ", "Select ") & "dates" //根據目前頁面的屬性是編輯之前的申請還是建立申請(通過變量 _editingRequest 進行控制),顯示不同的标題
2.3 ImageLeaveType - 假期類型圖示
Image = If(_editingRequest, LookUp(LeaveTypeCollection, Upper(type)=Upper(First(RequestEdit).LeaveType)).icon, _selectedLeaveType.icon)
//和上面的标簽控件很類似,也是根據目前頁面的屬性進行相應的後續處理。差別在于上面是直接固定設定好不同情況下的文字提示,這裡是根據情況設定不同的圖示。
//如果目前是編輯頁面,就通過LookUp函數從LeaveTypeCollection裡找出對應的假期類型圖示; 否則就利用上一節傳遞過來的變量 _selectedLeaveType, 其實也是個對象,通過 . 運算符來擷取所選的假期對應的圖示。
//這裡還涉及到第四節設定的一個集合 RequestEdit ,其中存儲的時使用者要編輯的請假申請資料,後續會繼續提及。
2.4 LabelLeaveType - 假期類型名稱
Text = If(_editingRequest, First(RequestEdit).LeaveType, _selectedLeaveType.type) //還是類似的邏輯,同時又用到了上一節傳來的變量
2.5 LabelCurrentBalanceText
Text = "Current balance: " //文字固定的提示标簽
2.6 LabelCurrentBalanceVal - 目前可用的假期天數
Text = LookUp(RequesterBalanceCollection, //Lookup函數的第一個參數:要去查詢的資料源,這裡設定的是第三節裡建立的集合 RequesterBalanceCollection。順便回憶一下,這個集合裡存儲的是員工目前可用的假期天數。
Upper(type)=If(_editingRequest, Upper(First(RequestEdit).LeaveType), Upper(_selectedLeaveType.type)), //Lookup 函數的第二個參數:查詢條件
Text(balance) &If(balance<2, " day", " days")) //LookUp函數的結果,這裡利用Text函數将依據 Type條件查詢傳回的結果,也就是假期天數(balance)轉成了文本,然後和文字 day 或者 days組合成新的文本。
上面四個控件在有資料時,所顯示出來的效果如下圖所示:
2.7 Rectangle9_4 - 區域分割線
2.8 LabelSelectDates - 提示性的文本資訊
Text = "Select Dates" //文字固定的提示标簽
2.9 Label19 -- 假期起始日期的提示性文本
Text = "*From" //文字固定的提示标簽
2.10 LeaveStartDatePicker - 用來選擇假期的起始日期
這個控件有四個關鍵的屬性設定:
- DateTimeZone = Local //日期的時區設定
- DefaultDate = If(_editingRequest, First(RequestEdit).StartDate, _reviewRequest, _leaveStart ,Today()) //設定頁面打開後,日期選擇器預設顯示的日期。這裡利用 IF(條件1,結果1,條件2,結果2,..., 條件n, 結果n, 預設結果 )的格式,定義了三種不同狀态的顯示日期: 編輯狀态,檢視狀态,其它狀态。
- OnChange = Set(_leaveStart, LeaveStartDatePicker.SelectedDate) //利用日期選擇器選擇了其它日期後,将新選的日期指派給變量 _leaveStart
- StartOfWeek = StartOfWeek.Sunday //每周的起始日期設定為周日,這個設定會直接影響到諸如第四節裡的假期天數計算邏輯。
2.11 Label19_1 - 假期結束日期的提示性文本
Text = "*From" //文字固定的提示标簽
2.12 LeaveEndDatePicker - 用來選擇假期的結束日期
運作邏輯和上面那個選擇起始日期的控件一樣,隻是從開始日期變成了結束日期。
- DateTimeZone = Local
- DefaultDate = If(_editingRequest, First(RequestEdit).EndDate, _reviewRequest, _leaveEnd, Today())
- OnChange = Set(_leaveEnd, LeaveEndDatePicker.SelectedDate)
- StartOfWeek = StartOfWeek.Sunday
2.13 Label1 - 當日期選擇不規範時(比如結束日期比開始日期還早),用來顯示警告資訊,提示使用者重新選擇正确的日期。
Text = If(LeaveStartDatePicker.SelectedDate > LeaveEndDatePicker.SelectedDate || And(!_editingRequest, LeaveStartDatePicker.SelectedDate < Today()), "Start date must occur on or " & If(LeaveStartDatePicker.SelectedDate > LeaveEndDatePicker.SelectedDate,"before end date", "after today"))
如下圖,出錯時的警告提示效果:
2.14 Rectangle9_5 - 區域分割線
2.15 ButtonNextSelectDates - 頁面最下面的下一步按鈕
OnSelect =
//**** 計算假期申請天數的預備代碼段 - 開始位置 ****和第四節裡計算假期申請天數的代碼段相同的邏輯
If(LeaveStartDatePicker.SelectedDate <= LeaveEndDatePicker.SelectedDate, //隻是這裡開頭是通過一個 IF語句來處理條件判斷,第四節裡是直接開始
Set(_inclusiveTotalDaysRequested, DateDiff(LeaveStartDatePicker.SelectedDate, LeaveEndDatePicker.SelectedDate, Days) + 1); //這裡也有點不同,但也隻是變量名稱的差别,邏輯上完全一樣。
Set(_numFullWeeks, RoundDown(_inclusiveTotalDaysRequested / 7, 0));
Set(_numFullDaysPartialWeek, _inclusiveTotalDaysRequested - _numFullWeeks * 7);
Concurrent(Set(_startWeekday, Weekday(LeaveStartDatePicker.SelectedDate)), Set(_endWeekday, Weekday(LeaveEndDatePicker.SelectedDate)));
//下面的IF 代碼段計算從所申請的總天數減去整周用掉的天數後,剩下的工作日天數
If(_numFullDaysPartialWeek = 6, If(_startWeekday <= 2, Set(_numPartialWeekdays, 5), Set(_numPartialWeekdays, 4) ),
_numFullDaysPartialWeek = 5, If(_startWeekday = 2, Set(_numPartialWeekdays, 5), _startWeekday = 1 || _startWeekday = 3 || _startWeekday = 4, Set(_numPartialWeekdays, 4), Set(_numPartialWeekdays, 3) ),
_numFullDaysPartialWeek = 4, If(_startWeekday = 2 || _startWeekday = 3, Set(_numPartialWeekdays, 4), _startWeekday = 1 || _startWeekday = 4, Set(_numPartialWeekdays, 3), Set(_numPartialWeekdays, 2) ),
_numFullDaysPartialWeek = 3, If(_startWeekday = 6 || _startWeekday = 7, Set(_numPartialWeekdays, 1), _startWeekday = 1 || _startWeekday = 5, Set(_numPartialWeekdays, 2), Set(_numPartialWeekdays, 3) ),
_numFullDaysPartialWeek = 2, If(_startWeekday = 7, Set(_numPartialWeekdays, 0), _startWeekday = 1 || _startWeekday = 6, Set(_numPartialWeekdays, 1), Set(_numPartialWeekdays, 2)),
_numFullDaysPartialWeek = 1, If(_startWeekday = 1 || _startWeekday = 7, Set(_numPartialWeekdays, 0), Set(_numPartialWeekdays, 1) ),
_numFullDaysPartialWeek = 0, Set(_numPartialWeekdays, 0)
);
Set(_workDaysInRequest, _numFullWeeks * 5 + _numPartialWeekdays);
Set(_holidaysInRequest, CountIf(Holidays, StartDate >= LeaveStartDatePicker.SelectedDate, StartDate <= LeaveEndDatePicker.SelectedDate));
Set(_requestedDays, _workDaysInRequest - _holidaysInRequest)
);
//**** 計算假期申請天數的代碼段 - 結束位置 - 最終請假的天數存儲在上面最後一個變量 _requestedDays 裡****
If(_editingRequest, Patch(RequestEdit, First(RequestEdit), {StartDate: LeaveStartDatePicker.SelectedDate, EndDate: LeaveEndDatePicker.SelectedDate, DaysCount:_requestedDays }) ; Navigate(EditRequestScreen, None),
_reviewRequest, Back(),
Navigate(SelectApproverScreen, None)
)
//最後這個 IF 是在上面計算完假期天數後,再根據不同的頁面狀态執行不同的動作。
//如果目前是編輯頁面,就把新選的日期通過 Patch 指令暫存到 RequestEdit 集合裡,然後跳轉到EditRequestScreen頁面;
//如果目前是檢視頁面,就直接傳回上一個頁面;
//其它狀态,就跳轉到SelectApproverScreen頁面。
附注:本節用到的函數:
Set, Concurrent, IF, Navigate, Reset, LookUp, First, Upper, Text, Patch
----------- 本節完成了對SelectDatesScreen頁面的解析,我們下一節再見------------