Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
0
Help us understand the problem. What is going on with this article?
@Rambosan

PowerAppsで業務シフト管理アプリ 改良版

概要

  • 作業者及び日付ごとの作業内容を選択してシフト管理ができるアプリの解説です。
  • 以前作ったアプリの改良版です。
  • いくつか気に入らない部分や反省点があり改良しました。

改良点

  • ギャラリーを4つ使用→3つ使用に
    • AddColumnsで直接データを取得できたのに何を思ったかギャラリーを介してしまったため改良。
  • シフトデータの取得を一回に
    • 作業者ごとにデータソースから取得→1週間分をまとめて取得(要件的に500件以内なので)
  • 保存ボタンを1つに
    • 入れ子ギャラリーの参照が空になる問題がクリアになったので。

アプリの仕様

前回と同じです。
左側に作業者リスト、上に一週間分の日付、その交わるセルに業務内容があります。
ドロップダウンで業務内容を変更して保存可能です。
データはSharePointリストに保管です。
Animation2.gif

SharePoint

前回と同じです。
データベースはSharePointリストです。
3つのテーブルを使います。
作業者名、業務内容はマスターテーブルを作成しシフト管理テーブルから参照します。
※お約束ですが列名は一旦英字で内部名を作成してから日本語にします。

image.png

実際の業務シフトテーブル
業務内容と作業者はデータ型を参照にしマスターから取得してあります。
image.png

PowerApps

画面の概要

ギャラリーを3つ使用します。
カレンダーから表示期間を選択、ドロップダウンで業務内容を選択し、保存ボタンで保存です。

image.png

スクリーンの設定

OnVisibleやOnHiddenで画面で使用する変数を設定します。
_defaultDateと_defaultToggle変数は、OnChangeを発火させるために値を2度セットしています。(次で解説)

OnVisible:

OnVisible
UpdateContext({
    _resetGallery:true,//ドロップダウンリストをリセットする変数
    _defaultDate:Blank(),//既定の日付:OnChange発火用
    _defaultToggle:true,//既定のトグル値:OnChange発火用
    _maxWeekday:If(Toggle_OnlyWeekday.Value = true,5,7)//平日のみ、土日の切り替え用
});
UpdateContext({
    _defaultDate:Today(),//既定の日付
    _defaultToggle:false//既定のトグル値
});

OnHidden:

OnHidden
UpdateContext({_resetGallery:false})

カレンダー表示部分

カレンダー部分の作成方法です。
前回とは少し異なります。

image.png

①日付の選択コントロール

OnChangeで、コレクションに選択日から一週間分のシフトデータと、カレンダー用の日付が入るようにします。

これらのコレクションは、画面のOnVisibleやレコード保存後にも更新する必要があります。
今回はOnChangeを任意のタイミングで発火させる小技を使って、コードの記述をこの一箇所で済ませます。

DefaultDate:_defaultDate
OnChange:

OnChange
If(!IsBlankOrError(Self.SelectedDate),
    //シフトデータを格納するコレクション
    ClearCollect(
        _weeklyTasks,
        Filter(
            SortByColumns(業務シフト管理テーブル ,"WorkingDate" ,Ascending),
            ThisRecord.作業日 >= Self.SelectedDate,
            ThisRecord.作業日 < DateAdd(Self.SelectedDate,11,Days)
        )
    );
    //カレンダー用のコレクション
    ClearCollect(
        _calenderLabelDates,
        FirstN(
            Filter(
                ForAll(
                    Sequence(11,0),
                    {Date:DateAdd(Self.SelectedDate,Value,Days)}
                ),
                Weekday(ThisRecord.Date,StartOfWeek.Monday) <= _maxWeekday
            ),
            7
        ) 
    )
);
  • 先程のスクリーンのOnVisibleで_defaultDateを一旦Blankにして直後にToday()を設定しています。
  • これによりOnVisible時に値が変更され、OnChangeイベントが実行されます。OnChangeが2回実行されますが、Blankのときはコードが実行されないよう、!IsBlankOrErrorで判定して分岐します。
  • これで任意のタイミングでOnChangeを発火させコードの使いまわしが可能になります。※現状FireEventのような関数がないため。
  • コレクション_weeklyTasksには、指定日から1週間分でフィルターしてデータを格納します。
  • コレクション_calenderLabelDatesには、指定日から1週間分の日付をセットします。
    ※Sequence(11・・は、土曜から平日のみ7日分表示したい場合、11日分が最大となるためです。

②トグル(平日のみ切り替え)

切り替えコントロールを配置します。
FalseText、TrueText:"平日のみ"
OnChange:UpdateContext({_maxWeekday:If(Self.Value = true,5,7)});
Default:_defaultToggle

③カレンダー用ギャラリー

横方向のギャラリーを追加します。
日付選択のOnChangeで作ったコレクションをセットします。
Items:_calenderLabelDates

ラベルを一つ配置し、
Text:Substitute(Text(ThisItem.Date,"[$-ja]mm/dd(dddd)"),"曜日","")

シフト表示ギャラリー部分

image.png

①親ギャラリーの設定

単純です。縦方向のギャラリーを配置します。
image.png

ギャラリー
Items:作業者マスターテーブル

ギャラリー内のコントロール
テキストラベルを2つ配置し以下を設定。

一つ目のText:Thisitem.作業者名
二つ目のText:CountRows(Gallery_TasksByWorker.AllItems)

二つめのラベルは非表示でOKです。後で一括保存ボタンを動作させるために必要になります。

②入れ子ギャラリーの設定

親ギャラリーの中に横方向のギャラリーを配置します。

image.png

ギャラリーのItemsは以下です。
先程のカレンダーギャラリーのレコードにAddColumnsでレコードID業務内容の列を加えます。
値は_weeklyTasksコレクションから日付と作業者名で検索して取得します。

Items
AddColumns(
    _calenderLabelDates As Dates,
    "RecordId",LookUp(_weeklyTasks,ThisRecord.作業日 = Dates.Date && ThisRecord.作業者.Value = ThisItem.作業者名).ID,
    "WorkType",LookUp(_weeklyTasks,ThisRecord.作業日 = Dates.Date && ThisRecord.作業者.Value = ThisItem.作業者名).業務内容
)

※ThisRecordはLookUp関数のレコードを参照しており、ThisItemはギャラリーのアイテムを参照しています。

次に、ギャラリーの中には以下のコントロールを配置します。
1.ドロップダウン:作業内容表示・編集用
2.チェックボックス:編集・更新判定用(変更するとTrueに)
3.ラベル:未保存表示用
image.png

1.ドロップダウン
作業内容を表示します。
Items:作業内容マスター
Value:業務内容
Default:ThisItem.WorkType.Value
AllowEmptySelection:True
Reset:_ResetGallery
Resetに設定した変数は外部からコントロールをリセットするために必要です。変数をtrueにするとリセットできます。

2.チェックボックス
編集したセルかどうかを判定するために必要になります。
レコードの値とドロップダウンの選択値を比較して、異なる場合にチェックが入る(true)ようにします。
ユーザーから編集できないように設定します。

Defaults:ThisItem.WorkType.Value <> Dropdown_WorkTypes.Selected.名前
DisplayMode:DisplayMode.Disabled

3.ラベル
未保存データを表示するラベルです。
Text:未保存
Visible:Checkbox_Unsaved.Value(チェックボックスの値です。)

保存、更新ボタン

image.png

保存ボタン

クリックしたとき、ギャラリーの中身を参照し未保存のチェックが入っているレコードのみ保存します。
その後、_defaultDate変数を変更して日付選択のOnChangeを発火させ、レコードを再読み込みさせます。

OnSelect:

OnSelect
ForAll(
    Gallery_Parent_Workers.AllItems As A,
    ForAll(Filter(A.Gallery_TasksByWorker.AllItems,ThisRecord.Checkbox_Unsaved.Value = true) As B,
        With({
                currentRecord:If(IsBlankOrError(B.RecordId),Defaults(業務シフト管理テーブル),LookUp(業務シフト管理テーブル,ID = B.RecordId)),
                currentWork:B.Dropdown_WorkTypes.Selected
            },
            Patch(業務シフト管理テーブル,currentRecord,
                {
                    作業者:{Id:A.ID,Value:A.作業者名},
                    作業日:B.Date,
                    業務内容:{Id:currentWork.ID,Value:currentWork.名前}
                }
            )
        )
    )
);
With(
    {prevDate:DatePicker_StartDate.SelectedDate},
    UpdateContext({_defaultDate:Blank()});
    UpdateContext({_defaultDate:prevDate});
)

  • 大体は前回と同じです。ForAllを入れ子にして子ギャラリーの中身を参照していきます。
  • 普通にやると、子ギャラリーであるGallery_TasksByWorker.AllItemsは空となりこのコードは動きません。(バグか仕様か)
  • 一時変数のCurrentRecordは、後のPatch関数の第二引数となる部分で、RecordIdにIDがあるかどうかで新規・変更を判定してレコードを代入します。
  • Patch関数で業務シフト管理テーブルのレコードを更新します。参照型の列は{Id:参照先ID, Value:表示値}で設定します。
  • 最後に日付選択コントロールのdefaultを更新してOnChangeを発火させます。
    • defaultを更新した後Resetを実行していませんが、仕様なのかdefaultを変更するだけでいいようです。

更新ボタン

日付選択のOnChange発火は保存ボタンと同じです。
With関数で一時変数prevDateに現在の値を保持しておき、Blank→prevDateと変更します。

OnSelect
Refresh(業務シフト管理テーブル);
With(
    {prevDate:DatePicker_StartDate.SelectedDate},
    UpdateContext({_defaultDate:Blank()});
    UpdateContext({_defaultDate:prevDate});
)
0
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Rambosan
製造業勤務。エンジニアを目指して勉強中。PowerPlatform好き。 非エンジニアでも使いこなせる人が増えれば良いと願って記事を書いています。

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
0
Help us understand the problem. What is going on with this article?