kintone
投稿日:

kintoneでクリニックの患者フォローを仕組み化 ― 来院リマインドと検査結果通知の管理術

皆さんこんにちは。kintoneアプリエンジニアのtomiokaです。

先日、内科・消化器科クリニックのお客様から「再診予定の患者さんへのフォローが看護師の記憶頼みになっていて、来院が途切れてしまう人が増えている」と相談がありました。

患者数約3000名、月の外来数が約800名という規模のクリニックです。医師2名、看護師4名、事務スタッフ3名で運営されていて、日々の診療だけでもかなり忙しい。そこに「次回来院の予定管理」「検査結果の通知」といったフォロー業務が加わると、どうしても漏れが出てしまいますよね。

実際、相談を受けた時点で来院中断率が12%にまで上がっていました。慢性疾患の患者さんが定期受診を中断してしまうと、病状の悪化リスクが高まります。クリニック側としても、継続的な通院が必要な患者さんのフォローが抜けてしまうのは経営面でも大きな課題です。

今回は、kintoneを使ってこの患者フォロー管理をどう仕組み化したのか、実装の内容をお伝えします。

この記事の想定読者

こんな状況に心当たりのある方に向けて書いています。

  • 医師2〜5名規模のクリニックで、患者のフォローアップに課題を感じている事務長・看護師長
  • 再診予定の管理がExcelや紙のメモに依存していて、対応漏れが起きている
  • 検査結果の通知を「誰が」「いつ」行ったか記録が残っていない
  • 来院中断者の増加に危機感を持っているクリニック運営者

現場の課題 ― なぜフォローが抜け落ちるのか

相談を受けて現場をヒアリングしてみると、問題の根本は「情報が人の記憶にしか残っていない」ことでした。

看護師さんが診療補助の合間に「○○さん、来週が再診予定だったはず」と思い出してカルテを確認する。それが日々の業務に埋もれてしまうと、フォローの電話をかけ忘れる。検査結果が届いても、通知済みかどうかがカルテの付箋メモだけで管理されていて、引き継ぎのときに漏れが発生する。

こうした状態が積み重なって、来院中断率12%という数字になっていました。月800名の外来のうち、約96名が予定通りに来院していない計算です。

Excelで管理しようとした時期もあったそうですが、患者数が3000名を超えてくると、Excelのフィルター操作だけでも手間がかかり、「結局見なくなった」とのことでした。

kintoneアプリの構成

今回は3つのアプリを連携させる構成にしました。それぞれの役割は以下のとおりです。

アプリ名役割
患者マスタアプリ患者の基本情報と次回来院予定日を管理。フォロー状態(未対応/リマインド済み/来院確認済み)を持つ
フォロータスクアプリリマインド連絡や検査結果通知などのタスクを管理。担当者・期限・ステータスを追跡する
検査結果通知アプリ検査結果の到着日・通知日・通知方法・通知者を記録。患者マスタとルックアップで紐付ける

ポイントは、患者マスタアプリに「フォロー状態」フィールドを持たせたことです。リマインドタスクを生成済みかどうかをこのフィールドで判定することで、二重にタスクが作られるのを防いでいます。

フィールド構成

患者マスタアプリ

フィールド名フィールドタイプ用途
患者番号文字列(1行)患者を一意に識別するID
患者氏名文字列(1行)患者のフルネーム
電話番号文字列(1行)リマインド連絡先
診療科ドロップダウン内科 / 消化器科
担当医ドロップダウン担当医師名
次回来院予定日日付次回の受診予定日
フォロー状態ドロップダウン未対応 / リマインド済み / 来院確認済み
備考文字列(複数行)特記事項

フォロータスクアプリ

フィールド名フィールドタイプ用途
患者番号文字列(1行)患者マスタとの紐付けキー
患者氏名文字列(1行)対象患者名
タスク種別ドロップダウンリマインド / 検査結果通知 / その他
タスク内容文字列(複数行)タスクの詳細
対応期限日付タスクの期限
ステータスドロップダウン未着手 / 対応中 / 完了
担当者ドロップダウンタスク担当者
対応メモ文字列(複数行)対応時の記録

リマインド対象を一括抽出するカスタマイズ

今回の実装の核になるのが、患者マスタアプリの一覧画面に設置した「リマインド対象を抽出」ボタンです。

このボタンをクリックすると、次回来院予定日が今日から7日以内で、まだフォローが済んでいない患者を自動で抽出し、フォロータスクアプリにリマインドタスクをまとめて生成します。毎朝、事務スタッフがこのボタンを押すだけで、その日対応すべきリマインド対象のリストが自動でできあがるわけです。

以下が実際のコードです。患者マスタアプリのJavaScriptカスタマイズとして設定します。

(function() {
  'use strict';

  // フォロータスクアプリのアプリID(環境に合わせて変更してください)
  var TASK_APP_ID = 100;

  // 一覧画面の表示イベント
  kintone.events.on('app.record.index.show', function(event) {
    if (document.getElementById('remind-btn')) {
      return event;
    }

    var headerSpace = kintone.app.getHeaderMenuSpaceElement();
    var button = document.createElement('button');
    button.id = 'remind-btn';
    button.textContent = 'リマインド対象を抽出';
    button.style.cssText =
      'padding: 8px 16px; background: #3498db; color: #fff;' +
      'border: none; border-radius: 4px; cursor: pointer; font-size: 14px;';

    button.addEventListener('click', function() {
      button.disabled = true;
      button.textContent = '処理中...';
      extractRemindTargets()
        .finally(function() {
          button.disabled = false;
          button.textContent = 'リマインド対象を抽出';
        });
    });

    headerSpace.appendChild(button);
    return event;
  });

  function extractRemindTargets() {
    var today = new Date();
    var remindDate = new Date();
    remindDate.setDate(today.getDate() + 7);

    var todayStr = formatDate(today);
    var remindDateStr = formatDate(remindDate);

    // 7日以内に来院予定かつ未対応の患者を取得
    var query =
      '次回来院予定日 >= "' + todayStr + '"' +
      ' and 次回来院予定日 <= "' + remindDateStr + '"' +
      ' and フォロー状態 in ("未対応")' +
      ' order by 次回来院予定日 asc';

    return kintone.api(kintone.api.url('/k/v1/records.json', true), 'GET', {
      app: kintone.app.getId(),
      query: query,
      fields: ['$id', '患者番号', '患者氏名', '次回来院予定日', '担当医', '電話番号']
    }).then(function(resp) {
      if (resp.records.length === 0) {
        alert('リマインド対象の患者はいませんでした。');
        return;
      }

      // フォロータスクアプリにリマインドレコードを一括登録
      var taskRecords = resp.records.map(function(rec) {
        return {
          患者番号: { value: rec['患者番号'].value },
          患者氏名: { value: rec['患者氏名'].value },
          タスク種別: { value: 'リマインド' },
          対応期限: { value: rec['次回来院予定日'].value },
          タスク内容: {
            value: rec['患者氏名'].value + '様(TEL: ' +
              rec['電話番号'].value + ')\n' +
              '次回来院予定日: ' + rec['次回来院予定日'].value + '\n' +
              'リマインドの電話連絡をお願いします。'
          },
          ステータス: { value: '未着手' }
        };
      });

      return kintone.api(kintone.api.url('/k/v1/records.json', true), 'POST', {
        app: TASK_APP_ID,
        records: taskRecords
      }).then(function(postResp) {
        // 患者マスタ側のフォロー状態を「リマインド済み」に更新
        var updateRecords = resp.records.map(function(rec) {
          return {
            id: rec['$id'].value,
            record: { フォロー状態: { value: 'リマインド済み' } }
          };
        });

        return kintone.api(kintone.api.url('/k/v1/records.json', true), 'PUT', {
          app: kintone.app.getId(),
          records: updateRecords
        }).then(function() {
          alert(postResp.ids.length + '件のリマインドタスクを作成しました。');
          location.reload();
        });
      });
    }).catch(function(err) {
      console.error(err);
      alert('エラーが発生しました: ' + (err.message || JSON.stringify(err)));
    });
  }

  function formatDate(date) {
    var y = date.getFullYear();
    var m = ('0' + (date.getMonth() + 1)).slice(-2);
    var d = ('0' + date.getDate()).slice(-2);
    return y + '-' + m + '-' + d;
  }
})();

コードのポイントを整理します。

  • app.record.index.show イベントで一覧画面のヘッダーメニューにボタンを追加しています
  • クリック時にREST APIで「次回来院予定日が7日以内」かつ「フォロー状態が未対応」の患者を取得します
  • 該当患者のリマインドタスクをフォロータスクアプリに一括登録します
  • 登録後、患者マスタ側のフォロー状態を「リマインド済み」に更新して二重生成を防止しています
  • ボタンの disabled 制御で、処理中の二重クリックも防いでいます

ハマりどころ

日付の比較クエリとフォーマットのずれ

kintoneの日付フィールドは YYYY-MM-DD 形式で格納されています。JavaScriptの new Date() はローカルタイムゾーンで日付オブジェクトを生成しますが、そのまま toString()toISOString() で文字列にすると、、、、kintoneのクエリで期待した日付範囲と一致しないことがあります。formatDate 関数で YYYY-MM-DD に明示的に整形するのが確実です。最初はここで「昨日の対象者が出てこない」と少し悩みました。

一括登録の100件制限

kintone REST APIの POST /k/v1/records.json は、1回のリクエストで登録できるレコード数が最大100件です。今回のクリニックは月の外来数が約800名で、7日以内のリマインド対象は多くても30〜40名程度だったので問題になりませんでしたが、、、、大規模な医療機関では対象者が100件を超えるケースもあり得ます。その場合は配列を100件ずつに分割してリクエストを送る処理が必要です。

ボタンの二重描画

kintoneの一覧画面は、絞り込み条件を変更したりページを切り替えたりすると app.record.index.show イベントが再度発火します。ボタンの存在チェック(document.getElementById('remind-btn'))を入れておかないと、、、、ヘッダーにボタンが2つ、3つと増殖していきます。地味ですが、kintoneカスタマイズでほぼ必ずと言っていいほど発生する定番のハマりどころです。

導入結果

アプリの導入から3か月が経過した時点で、お客様から以下の報告をいただきました。

  • 来院中断率が12%から5%に低下した
  • リマインド業務にかかっていた1日あたり約40分の作業が、ボタン1回のクリック(約10秒)に短縮された
  • 検査結果の通知漏れが月に8〜10件発生していたのが、導入後はゼロになった
  • 「誰がいつ連絡したか」の記録が残るようになり、看護師間の引き継ぎがスムーズになった

特に院長から「看護師が本来の診療補助に集中できるようになった」という声をいただけたのは、kintoneエンジニアとして嬉しい瞬間でした。

まとめ

今回はクリニックの患者フォロー管理をkintoneで仕組み化した事例をお伝えしました。

医療現場のフォロー業務は、患者さんの健康に直結する大事な仕事でありながら、日々の診療に追われてどうしても後回しになりがちです。kintoneを使って「忘れない仕組み」を作ることで、スタッフの負担を減らしつつ、フォローの質を上げることができます。

今回の実装で押さえておきたいポイントは以下の3つです。

  • 患者マスタに「フォロー状態」を持たせて、リマインドタスクの二重生成を防止する
  • 一覧画面のボタンからタスクを一括生成し、毎日のルーティンに組み込む
  • 検査結果の通知履歴を記録して、通知漏れと引き継ぎミスをなくす

こうした仕組みは、特別に高度な技術が必要なわけではありません。kintoneの標準機能とちょっとしたJavaScriptカスタマイズの組み合わせで実現できます。

株式会社ファストコーディングでは、kintoneのカスタマイズや業務アプリの構築を承っています。「うちのクリニックでもこういう仕組みを作りたい」「kintoneで患者管理ができるのか相談したい」という方は、お問い合わせフォームからお気軽にご連絡ください。