お知らせアプリでレコードの既読チェックカスタマイズをしてみよう

著者名:三宅 智子(サイボウズ株式会社)

目次

概要

メールの既読チェックと同じく、kintone でもたとえばお知らせアプリなどで、通知先のユーザーが確認してくれたかチェックしたいと思うことはありませんか?
本記事では、ボタンを生成してお知らせアプリで既読チェックをするカスタマイズを解説します。

完成イメージ

できあがりはこのようになります。
ユーザーが確認/Noted ボタンをクリックすると、そのユーザー名が別フィールドに記録され、既読チェックができます。
今回はおまけ要素として、日英両方のユーザーに対応します。

主なカスタマイズ内容は以下です。

  • お知らせが公開されたら、確認ボタンを表示する。
  • ユーザーが確認ボタンをクリックすると、そのユーザー名を別フィールドに記録する。
  • ユーザーが確認ボタンをクリックすると、既読済みのユーザー数を別フィールドに記録する。
  • 日本語/英語に対応する。

まず kintone アプリを作成して、そこに JavaScript カスタマイズを加えていきます。
では、開発していきましょう!

kintoneのアプリ作成

今回は既読チェックカスタマイズということで、お知らせアプリを作成します。

  1. 以下のフィールドを配置したお知らせアプリを作成してください。(大文字/小文字にご注意ください)
    詳細なアプリの作成方法は こちらのヘルプ(アプリをはじめから作成する) (External link) を参照してください。

    フィールドの種類 フィールド名 フィールドコード
    ユーザー選択 確認済みユーザー Noted_Users
    数値 確認済み数 Count
    スペース Button (要素IDを指します)

    上記以外のフィールドは、こちらのアプリ構成を参考にして設定してください。
    (赤枠内は、必須項目です)

  2. 次に、以下のとおりプロセス管理を設定します。
    詳細な設定方法は こちらのヘルプ(プロセス管理を設定する) (External link) を参照してください。

  3. 今回英語ユーザーにも対応したいので、設定します。英語の箇所を以下のとおりに設定してください。
    詳細な設定方法は こちらのヘルプ(言語ごとの名称を設定する) (External link) を参照してください。

これでいったん kintone 側の下準備は完了です。

JavaScriptカスタマイズ

アプリ作成が完了したら、JavaScript カスタマイズを加えていきます。
下の JavaScript ファイルを kintone のお知らせアプリに適用します。

サンプルコード

既読チェック用の JavaScript ファイルです。
アプリ作成者の言語設定が英語の場合は、ステータスのフィールドコードが違うので、次のとおり 12 行目のコードを修正してください。

言語設定が日本語の場合
12
statusCode: 'ステータス',
言語設定が英語の場合
12
statusCode: 'Status',
notedButton.js
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/*
 * Noted button sample program
 * Copyright (c) 2018 Cybozu
 *
 * Licensed under the MIT License
*/
(() => {
  'use strict';

  // Define variables
  const common = {
    statusCode: 'ステータス', // アプリ作成者の言語設定が英語の場合は、'Status'に変更
    button: 'Button',
    notedUsers: 'Noted_Users',
    count: 'Count'
  };

  const terms = {
    en: {
      icon: 'Noted',
      message: 'If you check this announcement, please click below Noted button.',
      publishedStatusName: 'Published',
      revsionError: 'Someone may update a record. Please try again.'
    },
    ja: {
      icon: '確認',
      message: 'このお知らせを確認された方は、下の「確認」ボタンをクリックしてください',
      publishedStatusName: '公開済み',
      revsionError: '誰かがレコードを更新しました。再度「確認」ボタンをクリックしてください。'
    }
  };
  const lang = kintone.getLoginUser().language;
  const switchLang = (terms[lang]) ? terms[lang] : terms.en;

  // Check if it is published
  const isPublished = (event) => {
    const status = event.record[common.statusCode].value;
    if (status === switchLang.publishedStatusName) {
      return true;
    }
    return false;
  };

  // Check if user has checked
  const hasClicked = (event) => {
    const notedUsers = event.record[common.notedUsers].value;
    const user = kintone.getLoginUser().code;
    for (let i = 0; i < notedUsers.length; i++) {
      if (notedUsers[i].code === user) {
        return true;
      }
    }
    return false;
  };

  // Update record when user click the button
  const updateRecord = () => {
    const user = kintone.getLoginUser().code;

    // Get latest record object
    const getBody = {
      app: kintone.app.getId(),
      id: kintone.app.record.getId()
    };
    return kintone.api(kintone.api.url('/k/v1/record', true), 'GET', getBody).then((resp) => {
      const record = resp.record;
      const revision = record.$revision.value;
      const notedUsers = record[common.notedUsers].value;
      notedUsers.push({code: user});
      const counts = notedUsers.length;

      const putBody = {
        app: kintone.app.getId(),
        id: kintone.app.record.getId(),
        record: {
          [common.notedUsers]: {
            value: notedUsers
          },
          [common.count]: {
            value: counts
          }
        },
        revision: revision
      };

      return kintone.api(kintone.api.url('/k/v1/record', true), 'PUT', putBody).then(() => {
        // Success
        location.reload();
      }).catch((error) => {
        // Error
        alert(switchLang.revsionError);
        location.reload();
      });
    });
  };

  // Append button
  const appendButton = (event) => {
    // If statement isPublished
    if (!isPublished(event) || hasClicked(event)) {
      return;
    }

    // Create button element
    const messageSpan = document.createElement('span');
    messageSpan.textContent = switchLang.message;
    const messageDiv = document.createElement('div');
    messageDiv.style.color = 'red';
    messageDiv.appendChild(messageSpan);

    const button = document.createElement('button');
    button.className = 'kintoneplugin-button-dialog-ok';
    button.title = 'noted_button';
    button.innerHTML = switchLang.icon + '<i class="fa fa-check-square-o" aria-hidden="true"></i>';
    button.addEventListener('click', updateRecord);

    // Append
    const space = kintone.app.record.getSpaceElement(common.button);
    space.appendChild(messageDiv);
    space.appendChild(button);
  };

  // Make the Noted Users and Count field disabled
  const editDisabled = (event) => {
    // Set not to be carried over at reuse
    if (event.reuse) {
      event.record[common.notedUsers].value = [];
      event.record[common.count].value = '';
    }
    event.record[common.notedUsers].disabled = true;
    event.record[common.count].disabled = true;
    return event;
  };

  // Detail show execution function
  const detailShowEvent = 'app.record.detail.show';

  kintone.events.on(detailShowEvent, (event) => {
    appendButton(event);
    return event;
  });

  // Edit show execution function
  const editShowEvents = [
    'app.record.edit.show',
    'app.record.create.show',
    'app.record.index.edit.show'
  ];

  kintone.events.on(editShowEvents, (event) => {
    editDisabled(event);
    return event;
  });
})();

また、FontAwesome と 51-modern-default.css を kintone に適用します。
notedButton.js と併せて、PC 用の JavaScript/CSS ファイルに追加してください。

  • FontAwesome
    • https://js.cybozu.com/font-awesome/v4.7.0/css/font-awesome.min.css
  • 51-modern-default.css( こちらのGithub URL (External link) より CSS ファイルを作成してアップロード)

すべてアップロードすると、以下のようになります。
アプリへの JavaScript/CSS ファイルのアップロードの方法は こちらのヘルプ(JavaScriptやCSSでアプリをカスタマイズする) (External link) を参照してください。

動作確認

設定が完了したら、最後に動作確認をしましょう。
今回は、日本語と英語に対応できていることを確認するため、画面表示がそれぞれの言語設定になっているユーザーでログインして動作を確認します。
言語設定を変更したい場合は、 画面の言語を切り替える (External link) や、 タイムゾーンを切り替える (External link) を参照してください。

  1. サンプルデータを登録して、日本語利用ユーザーで、「公開する」ボタンをクリックしてプロセスを進めます。

  2. 「確認」ボタンをクリックします。


    確認ボタンを押したユーザー名とカウントが記録されます。
    また、「確認」ボタンも消えるようになっています。

  3. 次は英語ユーザーで kintone にログインし直して、英語表記のチェックを行います。
    注意書きやボタンの言語が変わっていることを確認しましょう。
    「Noted」ボタンをクリックします。


    そうすると、またユーザー名とカウントが変更されることを確認します。

これで動作確認も完了です!お疲れさまでした。

サンプルコードの解説

簡単にサンプルコードのポイント解説をします。

可変なものはcommon変数にまとめる

フィールドコードなど可変なものは common 変数にまとめて、メンテしやすいようにしておきます。

10
11
12
13
14
15
16
// Define variables
const common = {
  statusCode: 'ステータス', // アプリ作成者の言語設定が英語の場合は、'Status'に変更
  button: 'Button',
  notedUsers: 'Noted_Users',
  count: 'Count'
};

ちなみに ES6 からは、オブジェクトのキーに変数の値を使用したい場合、変数名を [] で囲んで指定できます。

72
73
74
75
76
77
78
79
80
81
82
83
84
const putBody = {
  app: kintone.app.getId(),
  id: kintone.app.record.getId(),
  record: {
    [common.notedUsers]: {
      value: notedUsers
    },
    [common.count]: {
      value: counts
    }
  },
  revision: revision
};

ユーザーの言語設定による日英の出し分け

cybozu.com 上のユーザーの言語設定によって、注釈やボタン文言の日英出し分けを行っている部分です。この書き方は覚えておきましょう。
条件(三項)演算子 (External link) を使っています。

18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
const terms = {
  en: {
    icon: 'Noted',
    message: 'If you check this announcement, please click below Noted button.',
    publishedStatusName: 'Published',
    revsionError: 'Someone may update a record. Please try again.'
  },
  ja: {
    icon: '確認',
    message: 'このお知らせを確認された方は、下の「確認」ボタンをクリックしてください',
    publishedStatusName: '公開済み',
    revsionError: '誰かがレコードを更新しました。再度「確認」ボタンをクリックしてください。'
  }
};
const lang = kintone.getLoginUser().language;
const switchLang = (terms[lang]) ? terms[lang] : terms.en;

ボタンの表示/非表示判定

プロセスが「公開」/「Published」のもの、かつログインユーザーが未読の場合のみ「確認」/「Noted」ボタンを表示するように制御しています。

 97
 98
 99
100
101
102
// Append button
const appendButton = (event) => {
  // If statement isPublished
  if (!isPublished(event) || hasClicked(event)) {
    return;
  }

おわりに

いかがでしたでしょうか?既読チェックのカスタマイズ、応用すればいろんな場面で使えると思うので、ぜひ工夫してみてください。
レコード追加後にプロセスを進め忘れることが多い場合、「レコードを追加したら次のステータスに進めるかを尋ねるダイアログを出す」というアレンジもいいかもしれません。

注意事項

  • 上記のカスタマイズは、PC のみで動作します。
  • 日本語と英語ユーザー両方に対応しています。
  • 同時リクエストが過多になることにより、kintone への負荷は高まる可能性があります。
  • 同レコードの同時編集により、レコードを更新できない場合があります。
  • ユーザーフィールドに多くのユーザー情報が登録されることにより、画面描写は遅延する場合があります。
information

この Tips は、2018 年 10 月版 kintone と Google Chrome で動作を確認しています。