拆解PowerApps - 请假申请 - 4

接上一节,今天我们将集中解析HomeScreen 里最大的一个控件:GalleryRequests。

2.5 GalleryRequests

A. 控件的作用:
这个控件是用来列示用户当前所提交的请假申请。
最初没有申请的时候这个区域是空白的,如下图所示,点击按钮过滤时还会有相应的文本提示。


当提交过申请之后,这个区域就会显示用户所提交的申请。用户可以点击下图中的四个按钮来根据申请的状态进行过滤,这个过滤的实现在下一个控件GalleryFilters 里会进行说明。

B. Gallery 里的子控件
GalleryRequests 包含了六个子控件,对应关系可以参考上图。

C. 运行逻辑
GalleryRqeusts 控件主要做了下面几方面的设置:
-  首先,设置了数据源 Leave 以及相应的字段。(还记得这个 Leave 吧? 就是 第一节 提到的在OneDrive 里创建的那个Excel 文件里的一个工作表。 )

-  设置了 Items = Sort(     //基于参数 _requestTypeFilter 的值(这个值是从下个要介绍的GalleryFilters 控件获取的)对结果进行过滤。过滤出的数据会按开始时间进行降序排列。
    If( _requestTypeFilter="All",   // IF 语句的条件,判断是否选中了"All" 进行过滤。
      Filter(Leave, If(_managerView, Approver = _myProfile.UserPrincipalName, Requester = _myProfile.UserPrincipalName) )  //IF条件为真时, 也就是如果选中了"All",就从Leave表里所执行的过滤 (Filter) 语句
      Filter(Leave, Status=_requestTypeFilter && If(_managerView, Approver = _myProfile.UserPrincipalName, Requester = _myProfile.UserPrincipalName) ) ), StartDate, Descending)   // IF 条件为假时执行的过滤语句。这里黑体加粗的参数在下一节的解析里才会生成,届时再做介绍。

-  设置了 OnSelect = 
Set(_showDetails, true);  //这里是分号, 该Set 命令和后续的函数会组成函数链,一并执行。
Concurrent  //又是一个Concurrent 函数,解构一下看里面包含了几条子函数(找逗号就行,子函数之间都是用逗号分隔的)。
    Set(_selectedLeaveType, LookUp(LeaveTypeCollection, Upper(type) = Upper(ThisItem.LeaveType))),   //Concurrent 的子函数 1: 效果是 把 LookUp得到的假期类型结果赋值给变量  _selectedLeaveType。
//这里的LeaveTypeCollection在 第一节 介绍过,它在 App 属性里进行了初始化设置。 

    //**** 计算假期申请天数的预备代码段 - 开始位置 ****
    Set(_inclusiveTotalDaysRequested, DateDiff(ThisItem.StartDate, ThisItem.EndDate, Days) + 1);   //设置所选的 总天数。比如起始日选了9号,结束日选了15号,结果总天数就是 7 天。
    Set(_numFullWeeks, RoundDown(_inclusiveTotalDaysRequested / 7, 0));   //总天数涵盖的整周数。比如 10天就是涵盖了一个整周,14天涵盖了两个整周。
    Set(_numFullDaysPartialWeek, _inclusiveTotalDaysRequested - _numFullWeeks * 7);     // 去除整周的天数后,所剩下的天数。比如申请了10天,这里剩下的就是3天;申请了14天,这里剩下的就是 0 天。
    Set(_startWeekday, Weekday(ThisItem.StartDate));  //设置所选的开始那天是一周里的第几天,默认每周的第一天从周日开始算。如下图,起始日选了9号,这个_startWeekDay就等于 4.
    Set(_endWeekday, Weekday(ThisItem.EndDate)); //设置所选的结束那天是一周里的第几天,默认每周的第一天从周日开始算

// 下面的 IF 代码段是用来计算从所申请的总天数减去整周用掉的天数后,剩下的工作日天数, 并赋值给变量  "_numPartialWeekdays"。 
// 以下图的日历为例, 如果用户申请从 4号休息到 15号,下面的 IF 代码段就应该算出去掉  6 号到 12号这一整周之后,还剩下的工作日天数。也就是4、14、15共三天。

 。
    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)
    );   //拿第一条语句来解析一下这个逻辑:如果申请天数去掉整周后还剩了 6天,并且开始日期为周日或者周一,那么去掉整周后,剩下的工作日天数就是5天(6天的前提下,并且开始时星期天或者星期一,那么这6天理肯定只会包含周末的一天,要么是起始的那个星期日,要么起始是星期一就会涵盖一个星期六),否则如果起始日期不是周日或周一,那吗去掉整周天数后,剩下的工作日就是4天(因为这种情况下就必然会包括掉到星期六和星期日两天,工作日就剩下了 4天。)

    Set(_workDaysInRequest, _numFullWeeks * 5 + _numPartialWeekdays)   //Concurrent 的子函数 2:实际上是一个函数组合,从上面标红的一个Set函数开始,到这个标红的Set 函数结束。作用是用来计算假期申请所包含的工作日天数。
//最后这个标红的Set 函数把总共的工作日天数(整周的周数*5 + 去除整周后剩下的工作日天数_numPartialWeekdays), 赋值给到 _workDaysInRequest (注意:这里面可能还会包括法定假期,后续还得继续处理)

    Set(_holidaysInRequest, CountIf(Holidays, StartDate >= ThisItem.StartDate, StartDate <= ThisItem.EndDate))   //Concurrent 的子函数 3:计算所选的天数里有几天是法定假期, 这里的 Holidays 是保存在 OneDrive 那个Excel文件里的一个表,表名称就叫 Holidays。 后续有一个页面是专门用来维护这个节假日数据的。使用了 CountIf 函数来做计数。

     //**** 计算假期申请天数的预备代码段 - 结束位置 - 最终请假的天数存储在下面的变量 _requestedDays 里****    

    ClearCollect(RequestEditTemp, ThisItem)   //Concurrent 的子函数 4:将当前的数据存储到 RequestEditTemp 集合里。

    // 下面这段 IF 语句先判断是不是主管视图,如果是,就获取申请人信息、假期天数信息等,并判断是否和该主管其它下属的申请有冲突,供主管用来做出审批判断。
    If(_managerView // IF条件 。      

        Set(_requester, Office365Users.UserProfile(ThisItem.Requester));
        If(Office365Users.UserPhotoMetadata(_requester.Id).HasPhoto, Set(_requesterPhoto, Office365Users.UserPhoto(_requester.Id)), Set(_requesterPhoto, Blank()))  //获取申请人的Profile和头像信息
        Set(_requesterBalanceRecord, LookUp(Balance, Year = Text(Year(Now())) && EmployeeEmail = ThisItem.Requester));    //获取申请人假期可用天数
        ClearCollect(RequestOverlaps, Filter(Leave, EndDate >= ThisItem.StartDate && StartDate <= ThisItem.EndDate && Requester <> ThisItem.Requester));    //使用集合 RequestOverlaps 来存储所有下属的假期申请中存在的冲突数据
        If(CountRows(RequestOverlaps) > 0, Set(_requestOverlapMessage, Concat(Distinct(RequestOverlaps, Requester), Result, ", "))) //如果存在冲突,就利用函数 Concat() 把利经由 Distinct 函数去掉重复的申请人后合并成的一个字符串,赋值给变量 ")requestOverlapMessage"。 所实现的效果如下所示,就是主管在进行审批时,会有一个红色提示,告知主管当前这个用户的假期申请和其他用户的申请有日期重叠(这个界面后续会再具体介绍)。


// 以上为 IF 条件为True执行的代码段。    

        Set(_defaultApprover,  Office365Users.UserProfile(ThisItem.Approver));
        If(Office365Users.UserPhotoMetadata(_defaultApprover.Id).HasPhoto, Set(_defaultApproverPhoto, Office365Users.UserPhoto(_defaultApprover.Id)), Set(_defaultApproverPhoto, Blank()))     //获取审批人的 Profile 和头像信息
//  以上为 IF 条件为False执行的代码段。
     
    )   // IF 代码段结束。这个IF语句也是Concurrent 的子函数 5
);     //至此Concurrent 函数结束,同时,这里以分号结束表明后面还是同一个函数链

Set(_requestedDays, _workDaysInRequest - _holidaysInRequest);   //以分号结束表明后面还是同一个函数链。这个Set 很好理解,就是把利用上面计算申请天数预备代码段里得到的结果,最终计算出去掉法定假期后所申请的工作日天数,然后赋值给变量 "_requestedDays"。

//RequestEdit is the record the user is editing, whether they are a manager or employee
ClearCollect(RequestEdit, AddColumns(RequestEditTemp, "DaysCount", _requestedDays));   // 在上面定义的 RequestEditTemp 基础上,再添加一个 DaysCount字段,生成一个新的数据集合 RequestEdit,用来存储用户编辑的假期申请数据。
//这个 RequestEdit集合后续在用户要对申请的假期进行编辑、查看时会多次用到,在这里先提一句,留点印象。 
//这里还是以分号结束,表明后面还是同一个函数链。

If(_managerView,  Navigate(ManagerRequestDetailScreen, None), Navigate(HomeScreenPopup, None) ) // 最后一条语句,利用IF语句,判断当前视图是不是主管的视图,如果是就跳转到 ManagerRequestDetailScreen 屏幕,如果不是就跳转到 HomeScreenPopup 屏幕。

//至此,总体来看这个OnSelect 只有一个函数链,函数链里一次调用了Set、Concurrent、Set、ClearCollect 和 IF 五个函数。其中,Concurrent 又包含了 5段子函数,上面已经做了拆解,这里就不再赘述了。

附:本节用到的函数:
Sort(), Filtersetconcurrentlookup, weekdayIF, CountIf(计数)
---------先到这里,本节的几个 IF 代码段可以多看几眼,感受一下其中的逻辑思路。下一节我们继续拆解。----------


 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值