Monacaを使えば、誰でも簡単にスマートフォンアプリが開発できます。さらにそこにニフクラ mobile backendを組み合わせることで、データの保存や認証などのサーバが必要な機能をすばやく追加できます。
この連載記事では業務でよくある勤怠管理(出退勤入力)アプリを作るのを目標としています。全部で3回に分けて開設します。
- 認証機能を実装する
- データの保存と表示処理を実装する
- データをファイルストアに保存する
第2回目となる今回はデータの保存と表示処理の実装について解説します。
前回の記事はこちらになります。 Monacaとニフクラ mobile backendを使って勤怠管理アプリを作ろう【その1:認証機能を実装する】
home.htmlでの処理について
前回までで認証処理が終わって、home.htmlに戻ってくるところまで完了しました。今回は出勤(または退勤)ボタンを押して、それをログとしてmBaaSに記録する流れを作ります。
まず、home.htmlを初期化する処理を作成します。これはすでに記述してありますが、出退勤ボタンを押した際のイベントを設定しています。
// 初期化時(一回だけ)実行されます ons.getScriptPage().onInit = async function(e) { // 出退勤ボタンを押した際のイベント処理です this.querySelector('#record').onclick = record.bind(this); }
こちらもすでに記述されていますが、home.htmlを表示した際に毎回実行される処理です。
// この画面が表示される度に実行されます ons.getScriptPage().onShow = async function(e) { const page = this; // 1. ログインしていなければ、名前を登録する画面に遷移します // ログインユーザを取得します(第1回目に記述した内容) const user = ncmb.User.getCurrentUser(); if (!user) { // ログインしていないので config.html に遷移する document.querySelector('#tabbar').setActiveTab(2); return; } page.querySelector('#name').innerHTML = user.get('name'); // 現在時刻を表示する処理 callTimer(page); // 出退勤ボタンのラベル変更 changeStatus(page); // 他の働いている人たちの一覧表示 showWorkerList(page); } // タイマーで時間を更新します function callTimer(page) { setInterval(() => { const d = new Date; page.querySelector('#time').innerHTML = d.toLocaleString(); }, 1000); }
この処理の中で行われている changeStatus
、 showWorkerList
について後ほど確認します(callTimer
は上記に記載済みです)。
出退勤ボタンを押した際のイベントを作成する
まず出退勤ボタンを押した際のイベント、recordについて記述します。7と8番の関数については前述の初期状態での処理と同じものです。
async function record(e) { try { e.preventDefault(); // 1. 変数を準備する // 2. ACLを準備する // 3. データストアのデータを準備する // 4. 退勤の場合は勤務時間を記録する // 5. 保存する // 6. 出退勤状態を逆転する // 7. ステータスを変更する changeStatus(this); // 8. 勤務中の人リストを更新する showWorkerList(this); } catch (e) { console.log(e); } }
1. 変数を準備する
必要な変数は次の通りです。
- 現在時刻
- ログインユーザ
- 勤務中かどうかのフラグ
- ページ自身
これらを次のように準備します。
// 現在時刻 const time = new Date; // ログインユーザ const user = ncmb.User.getCurrentUser(); // 勤務中かどうかのフラグ const working = user.get('working’); // このページ自身 const page = this;
2. ACLを準備する
ログインユーザの時と同じく、保存データに対するACLも設定します。今回は、ユーザ自身にも書き込み権限を付与しつつ、管理者ロール(グループ)からも読み書き可能とします。adminロールは第1回目、管理画面で作成したものです。
const acl = new ncmb.Acl; acl .setUserReadAccess(user, true) .setUserWriteAccess(user, true) .setRoleReadAccess('admin', true) .setRoleWriteAccess('admin', true);
3. データストアのデータを準備する
データストアは ncmb.DataStore('クラス名')
で指定します。クラス名、は好きな名前を指定できます。データストアを new
とすることで、インスタンス(データストアの行相当)が生成されます。
データストアのインスタンスについては set('カラム名', '値')
の形式で自由にデータを設定できます。userはユーザオブジェクト、timeは時間、workingは真偽値になります。
const Record = ncmb.DataStore('Record'); const record = new Record; record .set('user', user) .set('acl', acl) .set('time', time) .set('working', !working);
4. 退勤の場合は勤務時間を記録する
退勤する場合、勤務時間を記録しておきます。処理は下記のコードを参考にしてください。rangeはミリ秒単位の数字になります。出勤時には逆に現在時刻をユーザのデータとして入れておきます。
if (working) { // 働いていたら、勤務時間を記録する const range = time.getTime() - new Date(user.get('workingStartTime')).getTime(); record .set('workingTime', range); } else { // 仕事の開始時間を記録しておく user.set('workingStartTime', time); }
5. 保存する
保存処理は save
メソッドです。新規保存時は save
、更新時は update
になります。これでデータストアにデータが送信されます。
await record.save();
6. 出退勤状態を逆転する
ユーザ自身は現在のステータスを出勤、退勤を逆転させます。こちらはすでにデータがありますので、update
メソッドで更新します。
await user.set('working', !working).update();
7. ステータスを変更する
ステータスを更新する changeStatus
関数は初期表示の際にも行っています。ここでまとめて解説します。この処理はユーザの勤務状態を取得し、それを画面に反映しています。勤務状態は user.get('working')
で取得できます。
changeStatus関数を下記のように変更してください。
function changeStatus(page) { // ログインユーザを取得し、その出退勤状態を判別します const user = ncmb.User.getCurrentUser(); const working = user.get('working'); page.querySelector('#record').innerHTML = `${working ? '退勤' : '出勤'}を記録する`; }
8. 勤務中の人リストを更新する
勤務しているほかの人たちを取得する showWorkerList
関数についてです。これはユーザデータを検索するのですが、 ncmb.User
の後に条件を追加して検索できます。
今回はイコール(=)条件である equalTo
メソッドを使って、勤務中のフラグが立っている人たちを検索しています。その結果は #workers
の中にOnsen UIのリストとして書き出しています。showWorkerList
関数を次のように書き直してください。
// 他の働いている人たちの一覧表示を行う関数 async function showWorkerList(page) { // ユーザデータを検索 const workers = await ncmb.User .equalTo('working', true) // 勤務中フラグが立っている人のみ .limit(1000) // 最大1,000件としています .fetchAll(); // 取得された結果を #workers に反映 page.querySelector('#workers').innerHTML = workers .map(w => `<ons-list-item>${w.get('name')}さん</ons-list-item>`) .join(''); }
(参考)record関数について
record関数の実装は以上です。実際の内容は次のようになります。参考にしてください。
async function record(e) { try { e.preventDefault(); // 1. 変数を準備する const time = new Date; const user = ncmb.User.getCurrentUser(); const working = user.get('working'); // 2. ACLを準備する const acl = new ncmb.Acl; acl .setUserReadAccess(user, true) .setUserWriteAccess(user, true) .setRoleReadAccess('admin', true) .setRoleWriteAccess('admin', true); // 3. データストアのデータを準備する const Record = ncmb.DataStore('Record'); const record = new Record; record .set('user', user) .set('acl', acl) .set('time', time) .set('working', !working); // 4. 退勤の場合は勤務時間を記録する if (working) { // 働いていたら、勤務時間を記録する const range = time.getTime() - new Date(user.get('workingStartTime')).getTime(); record .set('workingTime', range); } else { // 仕事の開始時間を記録しておく user.set('workingStartTime', time); } // 5. 保存する await record.save(); // 6. 出退勤状態を逆転する await user.set('working', !working).update(); // 7. ステータスを変更する changeStatus(page); // 8. 勤務中の人リストを更新する showWorkerList(page); } catch (e) { console.log(e); } }
履歴の表示
ではhistory.htmlに移動します。この画面では Record クラスに保存されているデータを取得して、画面に表示します。ここでは、画面を表示した際に使うのがよさそうなので、 onShow イベントを使います。最初、次のように書かれているはずです。 #records
に書き出す部分はOnsen UIの処理なので、コードを参照してください。
ons.getScriptPage().onShow = async function(e) { // Recordクラスを検索 // データを #records に書き出し // toTime関数は時間をフォーマットして書き出しているだけです。下記参照 this.querySelector('#records').innerHTML = records .map(r => `<ons-list-item> <span class="list-item__title"> ${toTime(r.get('workingTime'))} </span> <span class="list-item__subtitle"> ${new Date(r.get('time').iso).toLocaleString()}より </span> </ons-list-item>`) .join(''); }
Recordクラスを検索
Recordクラスの検索は次のように書きます。ここで知って欲しいのは、誰のデータが欲しいのか指定していないことです。この状態で検索したとしても、自分のデータしか返ってきません。mBaaSのACL(アクセス制限)によって、誰が読み込みできるのか指定しています。Recordクラスへの保存時に、自分とadminロールを持ったユーザーしか読み書きできないように指定したのを覚えているでしょうか。その結果、ほかのユーザーからは読み込みできないデータになっていますので、誰のデータという指定をしなくても問題なく運用できます。
下記処理を書き加えてください。勤務時間の履歴として表示されるはずです。
// Recordクラスを検索 const records = await ncmb.DataStore('Record') .limit(100) // 最大100件 .order('createDate', true) // 新しいものを上に .equalTo('working', false) // 勤務中フラグが立っていないものを対象 .exists('workingTime') // workingTimeが入力されているもの .fetchAll(); // 全データを取得
まとめ
ここまでで匿名認証、そしてデータストアへの保存と検索処理を学びました。ACLはmBaaSをセキュアに、安全に利用する上で大事な機能になりますので、ぜひ利用してください。
最後になる第3回ではデータストアにあるデータをCSVファイルとしてファイルストアに保存する処理を作成します。
次回の記事はこちらになります。
Monacaとニフクラ mobile backendを使って勤怠管理アプリを作ろう【その3:データをファイルストアに保存する】 - ニフクラ mobile backend(mBaaS)お役立ちブログ
前回の記事はこちらになります。 Monacaとニフクラ mobile backendを使って勤怠管理アプリを作ろう【その1:認証機能を実装する】