見出し画像

スペースポータルのボタンで在籍状況を更新する

やりたいこと

kintoneのスペースポータルにボタンを設置して、ボタンのクリックで他アプリのレコードを更新できるようにする。
実用例として、kintoneユーザーの「在籍状態」アプリのレコードを操作するカスタマイズに挑戦してみました。

cybozu developer networkの以下の記事を参考にさせて頂きました。
参考記事は、スペースポータルに設置したボタンで出勤・退勤の時刻を記録するタイムカードアプリを更新するカスタマイズ例です。

デモ画面

スペースポータルのタイトル下のヘッダー部分に、本日の日付と、kintone UI Componentを用いたボタンを表示(以降、KUCボタンと称します)して、クリック動作で「在籍状態」アプリのレコードを更新しています。
スペースポータルのヘッダーに表示したボタンClickだけで他アプリのレコードを更新するので、アプリを開く⇒目的のレコード表示⇒編集モードにするという煩わしい手順をワンクリックで簡略化しています。

  • スペースポータルのヘッダーに本日日付とボタンを表示します。

  • 在籍中・離籍中ボタンClickでログインユーザー名+本日日付をキーにして「在籍状態」アプリのレコードを検索します。

  • 検索キー(ユーザー名+日付)が一致したレコードを更新します。見つからない(本日の在籍記録が無い)場合は、新規レコードを作成します。

  • 同アプリのレコード一覧表をスペースポータルに表示し、ボタンクリック後に画面をリフレッシュ表示して、在籍状態を最新表示にしています。(デモ画面は、CSSでカスタマイズしたアラートを表示しています)

デモ画面1

カスタマイズの手順

カスタマイズの手順は、以下の通りです。

  1. 在籍状態アプリの作成とフィールドコードの設定

  2. カスタマイズ用Javascriptコードの準備

  3. kintone UI Componentのライブラリをアップロード

  4. カスタマイズ用Javascriptコードをアップロード

1.在籍状態アプリの作成と設定

アプリの新規作成で、以下の通りフォームを作成します。
 ユーザー名:ユーザー選択型
 日付:日付型
 在籍状態:文字列1行型
 備考:文字列1行型
フィールド名とフィールドコードは同じ名前にしています。

アプリのフォーム設定画面

2.カスタマイズ用Javascriptコードの準備

以下のサンプルコードをコピーして文字コード「UTF-8」で保存します。

// * Kintoneのスペース上部にボタンを設置して在籍状態アプリを更新
// * Sample Programe
// * Copyright (c) 2025 Application Utilization Study Group
// * Licensed under the MIT License
// ------------------------------------------------------------
(() => {
  'use strict';

  // 初期設定
  const CONFIG = {
    TARGET_SPACE_ID: '99', // 対象のスペースID
    TARGET_APP_ID: 123,    // 更新先アプリのアプリID
    FIELDS: {
      USER_NAME: 'ユーザー名',	// ユーザー名のフィールドコード
      DATE: '日付',          	// 日付のフィールドコード
      STATUS: '在籍状態'  	// 在籍状態のフィールドコード
    }
  };

  // スペースポータル表示イベント
  kintone.events.on('space.portal.show', (event) => {
    // スペースIDが不一致なら何もしない
    if (event.spaceId !== CONFIG.TARGET_SPACE_ID) {
      return event;
    }

    // スペース上側の要素を取得
    const spaceEl = kintone.space.portal.getContentSpaceElement(event.spaceId);

    // 本日日付表示の設定
    const today = new Date();
    const todayStr = new Intl.DateTimeFormat('ja-JP', {
      year: 'numeric',
      month: 'long',
      day: 'numeric',
      weekday: 'short'
    }).format(today);

    const displayDateDiv = document.createElement('div');
    displayDateDiv.id = 'displayDate';
    displayDateDiv.innerText = todayStr;
    displayDateDiv.style.fontSize = '26px';  // フォントサイズを26pxに設定
    displayDateDiv.style.marginLeft = '20px'; // 左マージンを20pxに設定
    spaceEl.appendChild(displayDateDiv);

    // ボタンを作成
    const buttonOK = new Kuc.Button({
      text: '在籍中',
      type: 'submit',
      id: 'Zaiseki'
    });

    const buttonCancel = new Kuc.Button({
      text: '離籍中',
      type: 'alert',
      id: 'Riseki'
    });

    // ボタンにイベントリスナーを追加
    buttonOK.addEventListener('click', () => {
      handleButtonClick('在籍中');
    });

    buttonCancel.addEventListener('click', () => {
      handleButtonClick('離籍中');
    });

    // ボタンコンテナを作成
    const buttonContainer = document.createElement('div');
    buttonContainer.style.display = 'flex';
    buttonContainer.style.gap = '10px';
    buttonContainer.style.margin = '20px';

    // ボタンをコンテナに追加
    buttonContainer.appendChild(buttonOK);
    buttonContainer.appendChild(buttonCancel);

    // スペース要素にボタンを追加
    spaceEl.appendChild(buttonContainer);

    return event;
  });

  // 本日日付を取得する関数
  const getTodayDate = () => {
    const today = new Date();
    return `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, '0')}-${String(today.getDate()).padStart(2, '0')}`;
  };

  // レコードを検索する関数
  const searchRecord = async () => {
    const today = getTodayDate(); // 現在の日付を取得
    const query = `${CONFIG.FIELDS.USER_NAME} in (LOGINUSER()) and ${CONFIG.FIELDS.DATE} = "${today}" order by ${CONFIG.FIELDS.DATE} desc limit 1`;
    const params = {
      app: CONFIG.TARGET_APP_ID,
      query: query
    };

    try {
      return await kintone.api(kintone.api.url('/k/v1/records', true), 'GET', params);
    } catch (error) {
      console.error('レコード検索中にエラーが発生しました:', error);
      throw error;
    }
  };

  // レコードを更新する関数
  const updateRecord = async (recordId, status) => {
    const params = {
      app: CONFIG.TARGET_APP_ID,
      id: recordId,
      record: {
        [CONFIG.FIELDS.STATUS]: { value: status }
      }
    };

    try {
      return await kintone.api(kintone.api.url('/k/v1/record', true), 'PUT', params);
    } catch (error) {
      console.error('レコード更新中にエラーが発生しました:', error);
      throw error;
    }
  };

  // レコードを作成する関数
  const createRecord = async (status) => {
    const loginUser = kintone.getLoginUser(); // ログインユーザー情報を取得
    const today = getTodayDate(); // 現在の日付を取得
    const params = {
      app: CONFIG.TARGET_APP_ID,
      record: {
        [CONFIG.FIELDS.USER_NAME]: { value: [{ code: loginUser.code }] },
        [CONFIG.FIELDS.DATE]: { value: today },
        [CONFIG.FIELDS.STATUS]: { value: status }
      }
    };

    try {
      return await kintone.api(kintone.api.url('/k/v1/record', true), 'POST', params);
    } catch (error) {
      console.error('レコード作成中にエラーが発生しました:', error);
      throw error;
    }
  };

  // ボタンのクリックイベント処理
  const handleButtonClick = async (status) => {
    try {
      const response = await searchRecord();
      
      if (response.records.length > 0) {
        // レコードが見つかった場合は更新
        const recordId = response.records[0].$id.value;
        await updateRecord(recordId, status);
      } else {
        // レコードが見つからない場合は新規作成
        await createRecord(status);
      }
	    location.reload(); // ページをリフレッシュ更新
        alert(`在籍状態を「${status}」に更新しました。`);
    } catch (error) {
      console.error('処理中にエラーが発生しました:', error);
      alert('エラーが発生しました。詳細はコンソールを確認してください。');
    }
  };
})();

Javascriptコードの「初期設定」を行います。

  // 初期設定
  const CONFIG = {
    TARGET_SPACE_ID: '99', // 対象のスペースID
    TARGET_APP_ID: 123,    // 更新先アプリのアプリID
    FIELDS: {
      USER_NAME: 'ユーザー名',	// ユーザー名のフィールドコード
      DATE: '日付',          	// 日付のフィールドコード
      STATUS: '在籍状態'  	// 在籍状態のフィールドコード
    }
  };

初期設定のTARGET_SPACE_IDに対象のスペースIDを設定します。
スペースIDは、スペースポータル表示URLの末尾の数字です。
※本カスタマイズは、スペースIDが不一致の場合は動作しません。

初期設定のTARGET_APP_IDに、KUCボタンのクリックイベントで更新する「在籍状況」アプリのアプリIDを設定します。
FIELDSの各項目に、アプリのフィールドコード名を設定します。
フィールドコード名は、アプリの設定と合わせて下さい。

サンプルコードは、kintone UI ComponentのUMD版(バージョン1.17.1)を利用することを前提にしています。
kintone UI Componentの実装方法は、以下の記事を参考にしてください。

アップロード画面

3.カスタマイズ用Javascriptコードをアップロード

intoneシステム管理>カスタマイズ>JavaScript / CSSでカスタマイズ
で表示される「kintone全体のカスタマイズ」の画面にアップロードします。
アップロードの順番は、kintone UI Componentのライブラリを先に指定し、その後にサンプルコード(ファイル名は自由)をアップロードします。
最後に「保存」ボタンを押します。


デモ画面2(応用例)

離籍理由をドロップダウンから選択できるようにしたバージョンです。
お客様の本番環境は、こちらのバージョンで運用中です。
ドロップダウンには、kintone UI Componentを使用しています。
工夫次第でこの様なカスタマイズも可能です。

デモ画面2

終わりに

スペースポータルに設置するボタンの実用例を考え中に、お客様の事務所の「行き先掲示板」を見て、これをアプリ化しようと思いつきました。

スペースポータルは、kintoneユーザーがログインして所属スペースに移動した際に必ず見る画面なので、ボタンで「在籍・離籍」の報告がワンクリックで出来れば、手書きの「行き先掲示板」が不要になると考えたのです。

実際には、手書き派の方は手書きの「行先掲示板」まま、アプリ派の方は、アプリにだけ登録するという運用状態なので、両方見ないと在籍状態が分からないという混沌状態にはまっています(苦笑)
解決策として手書きの「行先掲示板」を撤去する粗治療を実行予定ですw

運用方法を工夫すれば、出勤・退勤の時間管理にも利用出来ると思います。
※レコードの作成日時を「出勤時間」と見做すことが出来ます。
※離籍ボタンの最終更新日時を「退社時間」と見做すことが出来ます。
モバイル対応すれば、外出中でも退勤報告が可能になるかもしれません。

今回も最後まで読んで頂いてありがとうございました。

いいなと思ったら応援しよう!

アプリ活用研究会
よろしければサポートお願いします! いただいたサポートは、note記事制作の活動費に使わせていただきます!