FJCT_ニフクラ mobile backend(mBaaS)お役立ちブログ

スマホアプリ開発にニフクラ mobile backend(mBaaS)。アプリ開発に役立つ情報をおとどけ!

Monacaとニフクラ mobile backendを使って勤怠管理アプリを作ろう【その2:データの保存と表示処理を実装する】

f:id:mbaasdevrel:20200915154903p:plain

Monacaを使えば、誰でも簡単にスマートフォンアプリが開発できます。さらにそこにニフクラ mobile backendを組み合わせることで、データの保存や認証などのサーバが必要な機能をすばやく追加できます。

この連載記事では業務でよくある勤怠管理(出退勤入力)アプリを作るのを目標としています。全部で3回に分けて開設します。

  1. 認証機能を実装する
  2. データの保存と表示処理を実装する
  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);
}

この処理の中で行われている changeStatusshowWorkerList について後ほど確認します(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 ? '退勤' : '出勤'}を記録する`;
}

f:id:mbaasdevrel:20200915154853p:plain

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('');
}

f:id:mbaasdevrel:20200915154903p:plain

(参考)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:認証機能を実装する】

中津川 篤司

中津川 篤司

NCMBエヴァンジェリスト。プログラマ、エンジニアとしていくつかの企業で働き、28歳のときに独立。 2004年、まだ情報が少なかったオープンソースソフトの技術ブログ「MOONGIFT」を開設し、毎日情報を発信している。2013年に法人化、ビジネスとエンジニアを結ぶDXエージェンシー「DevRel」活動をスタート。