2016年10月31日月曜日

今日からシステムテストです

システムテストと改善

前回でシステム開発が完了しました。今日からシステムテストです。まず,データをORCAで入力してみます。入力したデータがスマホアプリで参照できることを確認します。また,表示の仕方はこれでよいか,表示する内容はこれで十分か,不要なものはないか,そういった視点でも確認していきます。これまでわかっている問題点を列挙してみます。
  • 患者基本情報に禁忌・アレルギー・感染症・コメントを表示する
  • スタイルシートを使って文字の大きさ,出力位置を調整する
また,これ以外にも何か問題はないか話し合ってみます。
例えば
診療行為が当日分しか表示されない(期間を指定できるようにした方が良いのでは?)
  • 画面が白黒で淋しい(色を付けたほうが良いのでは?)
  • ORCAの機能で他にもスマホを使ってできたらよいものはないか(たとえば予約など)

システム評価と方法

システム評価の方法として詳しい先生に評価をお願いすると決めました。とは言ってもアプリを見せて評価しろではあんまりです。アプリをどのように見てもらい,どのような観点で評価してもらうか,評価用アンケート用紙を作成する必要があるでしょう。

卒業論文

予定では今日までで第2章の方法を書き終えて,今日から第3章の結果を書くことになっています。結果は「アンケート結果の集計」となっていますが,学生からアンケートをとるのはやめたので,ここは先生方から評価してもらった結果を書くことになります。とはいえ,まだ評価してもらっていないので,まずはどのように評価してもらうかを考えなければなりません。

2016年10月24日月曜日

いよいよORCA Client Ver.1.0の仕上げです

前回は病名一覧画面を作りました。今回は最後に診療行為一覧画面を作成してアプリを完成させます。

診療行為一覧画面

この画面は,病名一覧画面(detail-page)において「Add a note」ボタンがタップされたときに表示します。

作成手順は以下の通りです。
  1. 診療行為一覧画面(medical-page)を作成する。これは,病名一覧画面とほとんど同じです。detail.htmlをコピーして作成すればよいでしょう。HTML名はmedical.htmlとします。
  2. 病名一覧画面(detail.html)で「Add a note」を「診療情報」と改め,このボタンがタップされたとき,診療行為一覧画面を表示するようにjavascriptを修正する。
  3. medical-pageが表示されたときのjavascriptを作成する。これも,病名一覧画面の場合とほとんど同じになる。診療行為を取得するには日レセAPIの診療情報の返却を使う。
なお,診療行為一覧画面の上部には,病名一覧画面と同様に患者基本情報を表示する。

2016年10月17日月曜日

卒論までのスケジュールを変更しました

システム開発は順調に進んでいるため,卒論提出までのスケジュールを修正しました。

卒論提出までのスケジュール(10月17日修正)
前回のゼミで患者基本情報をORCAからとってくるところを作りました。とってくる項目としては氏名,カナ氏名,性別,生年月日,住所,電話番号などの基本情報に加えてORCAの登録画面から入力できる禁忌,アレルギー,感染症,コメントも出しましょう。
ORCAの登録画面を以下に示します。

ORCA登録画面

なお,ORCAから患者基本情報をとってくるAPIについてはここを見てください。

患者病名情報


次は,患者病名一覧の表示です。患者病名情報は患者基本情報の下部に出します。

ORCAクライアント(患者病名一覧)

 この情報はORCAの病名登録画面(下図)から登録した情報を患者病名情報の返却APIによって取得して出力します。

ORCA(病名登録画面)

病名一覧は傷病名と開始日,転帰日,転帰,疾患区分などを表示すればよいでしょう。可能であれば,主病名,疑い,原疾患,合併症なども表示するとよいのかもしれません。

プログラムの修正と追加


病名情報は詳細画面(detail-page)を表示したタイミングで出力します。この画面の上部には患者情報が出力されています(ORCAクライアント(患者病名一覧)参照)。
まず,ORCAから患者病名情報をとってくる関数getDiseaseData()を作成します。これは,患者一覧情報をとってくる関数getPatientList()とほとんど同じです。異なるのはurl,requestXML,そしてORCAのレスポンスからDisease_Informationを探してそれを変数diseaseDataへセットすることくらいでしょうか。もちろんdiseaseDataはグローバル変数として定義しておかねばなりません。
 次は,詳細画面が表示されたときのイベントハンドラの修正です。まず,最初にgetDiseaseData()を実行して病名情報を取得します。次いで,取得した病名情報を使ってHTMLを編集していきます。この辺りの書き方は患者一覧画面(list-page)とほとんど変わりませんね。

卒論


卒論は,前回「第1章 はじめに」を書きました。今回は添削にしたがって修正してきているはずですね。そして,今日からは「第2章 方法」を書いていきます。ここにはシステム開発の方法と開発したシステムの評価方法を書きます。

システム開発の方法

 

ここには,システム構成や開発に用いた技術や開発ツールを書けばよいでしょう。システム構成は図にするとわかりやすいと思います。システム要素はORCAサーバとORCAクライアントであるスマホです。その間を無線で結んでいます。
開発に用いた技術はなんといってもORCAの日医標準レセプトAPIです。 これなくして今回のシステム開発は不可能でした。このWeb APIをスマホからAjaxを用いて呼び出し,必要なデータを取得して画面に出力したのです。
スマホアプリはHTML5ハイブリッドアプリ開発手法を用いて開発しました。これは,Cordovaという仕組みを使ってHTML5レイヤーからスマホのネイティブレイヤーを呼び出す開発手法です。そのため,開発者はHTML5とjavascriptそしてCSSの知識だけでスマホのデバイスを制御できるアプリを開発できます。
そして,私たちは,このHTML5ハイブリッドアプリを開発するための統合開発環境(IDE)としてMonacaを使用しました。Monacaはクラウド上の開発環境なので,ブラウザさえあれば他に何も必要としないという手軽さが開発効率を向上させました。
ORCAとスマホアプリの間の通信インターフェースはXMLを使っている点にも言及しておく必要があるでしょう。
ORCAとスマホアプリがこんなに簡単に接続できたのはこのWebAPIのおかげです。通信の標準化といえばHL7やDICOMが取沙汰されることが多いですが,私はWebAPIを公開することが相互接続性を高めるキーポイントだと考えています。APIが公開されていればシステムの中身を知らなくとも簡単な処理でデータにアクセスできます。ある意味,WebAPIを公開することが標準化の究極の姿ではないかと考えています。

開発したシステムの評価方法


これはとても難しい問題です。しかし,研究というからにはシステムを開発しましただけでは終われません。開発したシステムをきちんと評価してこそ研究と呼べます。
しかし,何をしたら評価したことになるのでしょう?それは実際に開発したシステムを利用してもらい,システムが在宅医療を支援したかどうかを評価することでしょう。その場合,利用者は医事会計システムとしてORCAを利用して在宅医療を行っている医師でしょう。
しかし,今回開発したシステムをそのような人に使ってもらうことは不可能です。ならば誰に評価してもらえばいいのか。学生?学生に正当な評価ができるでしょうか?ただ便利だと思うとか使いやすい(あるいは使いにくい)といった表面上の反応しか返ってこない危惧があります。ではどうすればよいか?
これを考えるのも卒研の一環です。みんなでどうすれば正当な評価ができるか考えてみましょう。
また,これも重要なことですが,本来,ORCAのような医事会計システムではなく,電子カルテシステムと連携してこそ有用なスマホアプリと考えてきましたが,手ごろな電子カルテがなかったのでやむなくORCAを使ったという経緯があります。とはいえ,ORCAでも有益なシステムとなり得ることを示さなければなりません。ORCAで管理できる情報の中で在宅医療に利用できる情報は何でしょうか?これを整理しておく必要がありそうです。
そこで,ORCAの各画面から入力できる全情報をエクセルに入力して,その中からスマホで見ることができると在宅医療で役立ちそうな項目に印をつけていきましょう。完成した表は卒論の目玉の一つとなるでしょう。

2016年10月3日月曜日

いいもの見つけた!-SurveyMonkey

こんなものがあるんだね。
SurveyMonke
これは卒研で使えるかもしれない。
無料アカウントはいつものやつで作ったので早速アンケートを作ってみよう。
今さらですが,こういうのもあるんだね。
Monacaで学ぶ初めてのプログラミング~モバイルアプリ入門編~

2016年10月1日土曜日

いよいよORCAとの通信です。

前回までは,スマホアプリはORCAと通信しているのではなく,ORCAが返してくるのと同じ形式のXMLデータを返してくるダミーのWebサーバと通信していました。それは,ORCAとの通信が少々込み入っているため,そのことに頭を悩ませてプログラム開発が先に進まないことを避けるためでした。
しかし,前回,スマホアプリの表示部分は出来上がったので,いよいよORCAと通信して”本物の”データを引っ張ってこれるようにします。
ORCAとの通信には日医標準レセプトAPIを使います。このAPIは,機能ごとにインターフェース(送信データ,応答データ)が決められています。そして,インターフェースは1つを除いてすべてXML形式でやりとりします。個々の機能の具体的なインターフェースは日医標準レセプトAPIで確認してください。
今作っているスマホアプリに必要な情報は

  1. 患者一覧情報
  2. 患者基本情報

の2つです。患者一覧情報のAPIはここを見てください。そして,患者基本情報のAPIはここです。

患者一覧情報


患者一覧情報を取得するにはORCAサーバにPOSTメソッドで要求データを送ります(17行目)。また,このAPIではXML形式でいくつかのデータをORCAへ送ります。開始日(10行目),終了日(11行目),そしてテスト患者区分(12)行目です。ORCAは指定した開始日と終了日の間に新規登録されたかまたは更新された患者情報の一覧を返してきます。このXMLデータは22行目に設定しています。このプログラムでは開始日を2016/4/1に,終了日を当日に設定してあります。
ORCAサーバへはXML形式の入力データだけでなく認証情報も送ります(19~21行目)。認証情報はユーザ名:パスワードをBase64でエンコードしたものをヘッダに付けて送ります(20行目)。
     function getPatientList() {
        var url = 'http://172.16.108.250:8000/api01rv2/patientlst1v2?class=01';
        patientList = null;

        var baseStartDate = '2016-04-01';
        var today = new Date();
        var baseEndDate = today.getFullYear() + '-' + zeroPadding(today.getMonth() + 1) + '-' + today.getDate();
        var requestXML = '<data>';
        requestXML += '<patientlst1req type="record">';
        requestXML += '<Base_StartDate type="string">' + baseStartDate + '</Base_StartDate>';
        requestXML += '<Base_EndDate type="string">' + baseEndDate + '</Base_EndDate>';
        requestXML += '<Contain_TestPatient_Flag type="string">1</Contain_TestPatient_Flag>';
        requestXML += '</patientlst1req>';
        requestXML += '</data>';

        $.ajax({
            type: 'POST',
            url: url,
            headers:{
                'Authorization' : 'Basic ' + window.btoa(g_user + ':' + g_passwd)
            },
            data: requestXML,
            contentType: "application/xml",
            async: false,
            cache: false,
            // レスポンスデータの形式
            dataType: "xml"
        }).done(function(xml, status, error){
            if (status == 'success') {
                patientList = $(xml).find('Patient_Information');
            } else {
                alert('文書データ取得失敗');
            }
        }).fail(function(xhr, status, error){
            var message = "xhr.status = " + xhr.status + ", xhr.statusText = " + xhr.statusText + ", status = " + status + ", error = " + error;
            alert('サーバから応答がありません: ' + message);
        });
    }
なお,7行目のzeroPaddingは数字の先頭に0を付けて2ケタにする(たとえば1を01にする)関数で以下のように定義されています。
//ゼロパディング
function zeroPadding( val ) {
    return ( "0" + val ).slice( -2 )
}

患者基本情報


患者基本情報はGETメソッドでサーバへ要求データを送ります(5行目)。GETメソッドではデータをクエリストリングとしてURLの一部として送ります(2行目)。?以降がそれです。クエリストリングは「パラメタ=値」という対を必要な数だけ&でつなげて書きます。
    function getPatientData(patientId) {
        var url = 'http://172.16.108.250:8000/api01rv2/patientgetv2?id=' + patientId;
        patientData = null;
        $.ajax({
            type: 'GET',
            headers:{
                'Authorization' : 'Basic ' + window.btoa(g_user + ':' + g_passwd)
            },
            url: url,
            async: false,
            cache: false,
            dataType: "xml"
        }).done(function(xml, status, error){
            if (status == 'success') {
                patientData = $(xml).find('Patient_Information');
            } else {
                alert('文書データ取得失敗');
            }
        }).fail(function(xhr, status, error){
            var message = "xhr.status = " + xhr.status + ", xhr.statusText = " + xhr.statusText + ", status = " + status + ", error = " + error;
            alert('サーバから応答がありません: ' + message);
        });
    }

患者病名情報


次は患者病名情報です。患者病名は詳細画面の下側に表示します(4~16行目)。 2行目のgetDiseaseDataが病名情報をORCAから取得する関数です。
    var diseaseData = null;

    $(document).on('pageinit', '#detail-page', function() {
        getDiseaseData(currentItem.id);
        var html = '';
        $(diseaseData).find('Disease_Information_child').each(function(){
            html += '<ons-list-item class="detail-item">';
            html += '<header>';
            html += '<span class="detail-item-date">' + $(this).find('Disease_StartDate').text() + '</span>';
            html += '</header>';
            html += '<p class="detail-item-diseaseName">' + $(this).find('Disease_Name').text() + '</p>';
            html += '</ons-list-item>';
        });
        $("#detail-item-list").html(html);
        var content = $("#detail-item-list").get(0);
        ons.compile(content);
        
        getPatientData(currentItem.id);
        var homeAddress = patientData.find('Home_Address_Information');
        var address = homeAddress.find('WholeAddress1').text();
        var phone = homeAddress.find('PhoneNumber1').text();
        $('.item-id', this).text(currentItem.id);
        $('.item-gender', this).text(currentItem.gender);
        $('.item-name', this).text(currentItem.name);
        $('.item-name-kana', this).text(currentItem.name_kana);
        $('.item-birthdate', this).text(currentItem.birthdate);
        $('.item-address', this).text(address);
        $('.item-phone', this).text(phone);
        $('.add-note-action-item', this).click(function () {
            // ここに Add a noteがタップされた時の処理を書く
        });
    });
getDiseaseData関数は次のようになります。患者一覧情報取得関数と同じようにXML形式のパラメタをPOSTメソッドをORCAサーバへ送ります。
    function getDiseaseData(patientId) {
        var url = 'http://172.16.108.250:8000/api01rv2/diseasegetv2?class=01';
        diseaseData = null;
        var requestXML = '<data>';
        requestXML += '<disease_inforeq type="record">';
        requestXML += '<Patient_ID type="string">' + patientId + '</Patient_ID>';
        requestXML += '<Base_Date type="string"></Base_Date>';
        requestXML += '</disease_inforeq>';
        requestXML += '</data>';
        $.ajax({
            type: 'POST',
            url: url,
            headers:{
                'Authorization' : 'Basic ' + window.btoa(g_user + ':' + g_passwd)
            },
            data: requestXML,
            contentType: "application/xml",
            async: false,
            cache: false,
            dataType: "xml"
        }).done(function(xml, status, error){
            if (status == 'success') {
                diseaseData = $(xml).find('Disease_Information');
            } else {
                alert('文書データ取得失敗');
            }
        }).fail(function(xhr, status, error){
            var message = "xhr.status = " + xhr.status + ", xhr.statusText = " + xhr.statusText + ", status = " + status + ", error = " + error;
            alert('サーバから応答がありません: ' + message);
        });
    }

診療行為情報


詳細画面で「Add a note」をタップされたら当該患者の診療行為を出力するようプログラムを改良します。

診療行為情報 (medical-page)

そのためには,まず,診療行為を表示する画面(html)を作成します。 単体ファイルでもons-templateとして作成しても構いません。 HTMLファイルの名前をmedical.html,ons-pageのidをmedical-pageとします。 ファイルの中身は詳細画面とほぼ同じで次のようになります。
<ons-template id="medical.html">
    <ons-page id="medical-page">

      <ons-toolbar>
        <div class="left"><ons-back-button>Back</ons-back-button></div>
        <div class="center">診療情報</div>
      </ons-toolbar>

      <ons-list modifier="inset" style="margin-top: 10px">
        <ons-list-item class="item">
          <ons-row>
            <ons-col width="60px"> 
              <div class="item-thum">
                <img src="" class="item-thum-photo" width="50px"></img>  
              </div>
            </ons-col>
            <ons-col>
              <header>
                <span class="item-id">id</span>
                <span class="item-gender">gender</span>
              </header>
              <p class="item-name">name</p>
              <p class="item-name-kana">name_kana</p>
              <p class="item-birthdate">birthdate</p>
              <p class="item-address">address</p>
              <p class="item-phone">phone</p>
            </ons-col>
          </ons-row>
        </ons-list-item>

        <ons-list-item modifier="chevron" id="add-note-action" class="add-note-action-item">
          <ons-icon icon="ion-chatboxes" fixed-width="true" style="color: #ccc"></ons-icon>
          症状詳記
        </ons-list-item>
      </ons-list>

      <ons-list id="medical-item-list" style="margin-top: 10px">
      </ons-list>

      <br>

    </ons-page>
</ons-template>
次に,この画面が表示された時の処理を書きます。 これも,詳細画面(detail-page)と変わりありません。
    var medicalData = null;
    
    $(document).on('pageinit', '#medical-page', function() {
        getMedicalData(currentItem.id);
        var html = '';
        $(medicalData).find('Medical_List_Information_child').each(function(){
            html += '<ons-list-item class="detail-item">';
            html += '<header>';
            html += '<span class="detail-item-date">' + $(this).find('Medical_Class_Name').text() + '</span>';
            html += '</header>';
            html += '<p class="detail-item-diseaseName">' + $(this).find('Medication_Name').text() + '</p>';
            html += '</ons-list-item>';
        });
        $("#medical-item-list").html(html);
        var content = $("#medical-item-list").get(0);
        ons.compile(content);
        
        getPatientData(currentItem.id);
        var homeAddress = patientData.find('Home_Address_Information');
        var address = homeAddress.find('WholeAddress1').text();
        var phone = homeAddress.find('PhoneNumber1').text();
        $('.item-id', this).text(currentItem.id);
        $('.item-gender', this).text(currentItem.gender);
        $('.item-name', this).text(currentItem.name);
        $('.item-name-kana', this).text(currentItem.name_kana);
        $('.item-birthdate', this).text(currentItem.birthdate);
        $('.item-address', this).text(address);
        $('.item-phone', this).text(phone);
        $('.add-note-action-item', this).click(function () {
            alert('病状詳記はまだ実装されていません!');
        });
    });
最後にORCAから当該患者の診療情報を取得する関数getMedicalDataを書きます。 これも患者一覧情報や患者病名情報の取得と同じようにPOSTメッセージでXMLデータを送信します。
    function getMedicalData(patientId) {
        var url = 'http://172.16.108.250:8000/api01rv2/medicalgetv2?class=03';
        medicalData = null;
        var today = new Date();
        var performDate = today.getFullYear() + '-' + zeroPadding(today.getMonth() + 1) + '-' + today.getDate();
        var requestXML = '<data>';
        requestXML += '<medicalgetreq type="record">';
        requestXML += '<InOut type="string">O</InOut>';
        requestXML += '<Patient_ID type="string">' + patientId + '</Patient_ID>';
        requestXML += '<Perform_Date type="string">' + performDate + '</Perform_Date>';
        requestXML += '<For_Months type="string">1</For_Months>';
        requestXML += '<Medical_Information type="record">';
        requestXML += '<Department_Code type="string">01</Department_Code>';
        requestXML += '</Medical_Information>';
        requestXML += '</medicalgetreq>';
        requestXML += '</data>';
        $.ajax({
            type: 'POST',
            url: url,
            headers:{
                'Authorization' : 'Basic ' + window.btoa(g_user + ':' + g_passwd)
            },
            data: requestXML,
            contentType: "application/xml",
            async: false,
            cache: false,
            dataType: "xml"
        }).done(function(xml, status, error){
            if (status == 'success') {
                medicalData = $(xml).find('Medical_List_Information');
            } else {
                alert('文書データ取得失敗');
            }
        }).fail(function(xhr, status, error){
            var message = "xhr.status = " + xhr.status + ", xhr.statusText = " + xhr.statusText + ", status = " + status + ", error = " + error;
            alert('サーバから応答がありません: ' + message);
        });
    }
なお,Add a noteをタップしたときに以下のようにすれば診療行為画面を表示することができます。
        $('.add-note-action-item', this).click(function () {
            app.navi.pushPage('medical.html');
        });