患者情報管理

ここではWijmo、InputManJSを利用して患者情報管理アプリの作成方法を確認することができます。

ここでは、患者情報管理アプリを作成する際のポイントを紹介します。 診察予約のタブ このタブでは、GcComboBoxとGcDateTimeで診察患者名と予約日を登録します。 登録したデータは、FlexGridに表示されます。 また、FlexGridでは、formatItemイベントを利用して行ヘッダーにアイコンを追加し、登録したデータの編集と削除ができるようにしています。 患者情報のタブ このタブでは、FlexGridをツリーグリッドとして表示し、患者情報を閲覧します。 診断書のタブ GcRichTextEditorで診断書を作成します。 GcRichTextEditorのテンプレート機能を利用して、三種類の診断書を選択できるようにしています。 BMIのタブ FlexSheetを利用して、患者情報をもとにBMI値とBMI判定を数式を設定し、値を自動計算しています。 過去データ分析のタブ FlexChartを利用して、以下のデータを表示しています。 症状別の累計値(折れ線グラフ) 月別の入院者数(棒グラフ) 月別の症状別患者数(円グラフ) 3.は2.の選択月を変更することで月が切り替わります。
import "./license.js"; import "bootstrap.css"; import "@mescius/wijmo.styles/wijmo.css"; import '@mescius/inputman/CSS/gc.inputman-js.css'; import '@mescius/inputman.richtexteditor/CSS/gc.inputman.richtexteditor.css'; import "./styles.css"; import * as wjFlexSheet from '@mescius/wijmo.grid.sheet'; import * as wjNav from "@mescius/wijmo.nav"; import * as wjCore from "@mescius/wijmo"; import * as wjGrid from '@mescius/wijmo.grid'; import * as chart from '@mescius/wijmo.chart'; import * as wjInput from '@mescius/wijmo.input'; import { InputMan } from '@mescius/inputman'; import * as GcRichtexteditor from '@mescius/inputman.richtexteditor'; import { getpaintData, getpaintInformation, getChartData, getChartPalette, getLineChartData, getPatientName, getreservationData } from './data'; InputMan.appearanceStyle = InputMan.AppearanceStyle.Modern; let theTabPanel = new wjNav.TabPanel('#theTabPanel', { isAnimated: true }); let patients = getpaintData(); // // 患者ツリー let patientsGrid = new wjGrid.FlexGrid('#patientsGrid', { headersVisibility: 'Column', childItemsPath: ['checks', 'patientInfomation'], autoGenerateColumns: false, columns: [ { binding: 'name', header: '病棟/病室', width: 150 }, { binding: 'status', header: '使用状況', cellTemplate: '<span class="badge bg-secondary bg-${text}">${text}</span>', align: 'center', width: 120 }, { binding: 'patientName', header: '患者名', width: 100, align: 'center' }, { binding: 'diagnosis', header: '診断名', width: 150, align: 'center' }, { binding: 'height', header: '身長(cm)', width: 80, align: 'center' }, { binding: 'weight', header: '体重(kg)', width: 80, align: 'center' }, { binding: 'age', header: '年齢', width: 60, align: 'center' }, { binding: 'bloodPressure', header: '血圧', width: 100, align: 'center' }, { binding: 'hospitalizationDay', header: '入院日', width: 100, align: 'center' }, { binding: 'doctorAssigned', header: '担当医', width: 100, align: 'center' }, ], itemsSource: patients, selectionMode: 0 }); let patientsData = getpaintInformation(patients); let patientSheet = new wjFlexSheet.FlexSheet('#bmiSheet'); patientSheet.addBoundSheet('BMI値', new wjCore.CollectionView(patientsData)); patientSheet.deferUpdate(() => { patientSheet.frozenRows = 1; patientSheet.columns.getColumn('患者名').isReadOnly = true; let column = patientSheet.columns.getColumn('BMI'); column.format = 'n2'; //診断名、血圧、担当医の列は非表示にする patientSheet.columns.getColumn('診断名').visible = false; patientSheet.columns.getColumn('血圧').visible = false; patientSheet.columns.getColumn('担当医').visible = false; //BMI計算式の設定 for (let rowIdx = 1; rowIdx < patientSheet.rows.length; rowIdx++) { patientSheet.setCellData(rowIdx, 5, "=E" + (rowIdx + 1) + "/(D" + (rowIdx + 1) + "/100)^2"); } // BMI判定式の設定 for (let rowIdx = 1; rowIdx < patientSheet.rows.length; rowIdx++) { patientSheet.setCellData(rowIdx, 6, "=IF(F" + (rowIdx + 1) + "<=18.5,\"低体重\",IF(F" + (rowIdx + 1) + "<=25,\"普通体重\",IF(F" + (rowIdx + 1) + "<=30,\"肥満(1度)\",\"肥満(2度以上)\")))"); } }); patientSheet.cellEditEnding.addHandler((s, e) => { //年齢の列で入力値を18から100歳の間に制限 if (e.col === 1) { const value = s.activeEditor.value; if (value < 18 || value > 100) { e.cancel = true; alert('年齢は18歳以上100歳未満で入力してください。'); } } else if (e.col === 3) { const value = s.activeEditor.value; if (value < 130 || value > 230) { e.cancel = true; alert('身長は130cm以上230cm未満で入力してください。'); } } else if (e.col === 4) { const value = s.activeEditor.value; if (value < 40 || value > 150) { e.cancel = true; alert('体重は40kg以上150kg未満で入力してください。'); } } }); const diagnosisEditor = new GcRichtexteditor.InputMan.GcRichTextEditor( document.getElementById("diagnosisTextArea"), { plugins: [GcRichtexteditor.InputMan.GcRichTextEditorPluginItem.All], menubar: [], baseUrl: '$DEMOROOT$/lib/purejs/node_modules/@mescius/inputman.richtexteditor/JS', toolbar: ["NewDocument", "preview", "print", 'h1', 'h2', 'h3', 'h4', 'h5', 'separateline', "undo", "redo", 'forecolor', 'backcolor', 'bold', 'italic', 'underline', 'separateline', "outdent", "indent", 'bulList', 'numList', 'separateLine', 'Link'], toolbarMode: GcRichtexteditor.InputMan.GcRichTextEditorToolbarMode.Wrap, contextmenu: [], templates: [ { title: "診断書(簡易)", content: "<H1 style=\"text-align:center\"><u>診 断 書</u></H1><b>住所:〒 </b><br><b>氏名:</b><br><b>診断:</b><br><b>所見:</b><br><H3 style=\"text-align:center;\">上 記 の 通 り 診 断 し ま す</H3><div style=\"text-align:right;\"><b>医師名:_____</b> <br><br>発行日:________年____月____日<br><br>※この診断書は、医師法第XX条に基づき発行されたものです。</div>", }, { title: "診断書(表形式)", content: `<H1 style=\"text-align:center\"><u>診 断 書</u></H1> <table border=\"1\" style=\"width:100%;border-collapse:collapse\"><tbody> <tr><th style=\"width:20%;text-align:left;padding:8px;background-color:#F0F0F0;\">住所</th><td style=\"text-align:left;padding:8px;\">〒 </td></tr><tr><th style=\"width:20%;text-align:left;padding:8px;background-color:#F0F0F0;\">氏名</th><td style=\"text-align:left;padding:8px;\"></td></tr><tr><th style=\"width:20%;text-align:left;padding:8px;background-color:#F0F0F0;\">診断</th><td style=\"text-align:left;padding:8px;\"></td></tr><tr><th style=\"width:20%;text-align:left;padding:8px;background-color:#F0F0F0;\">所見</th><td style=\"height:100px;text-align:left;padding:8px;vertical-align:top;\"></td></tr> </tbody></table><H3 style=\"text-align:center;\">上 記 の 通 り 診 断 し ま す</H3><div style=\"text-align:right;\"><b>医師名:_____</b> <br><br>発行日:________年____月____日<br><br>※この診断書は、医師法第XX条に基づき発行されたものです。</div>`, }, { title: "健康診断書", content: `<H1 style=\"text-align:center\"><u>健康診断個人票</u></H1><table border=\"1\" style=\"width:100%;border-collapse:collapse;font-size:12px;\"><tbody> <tr><td colspan=\"2\" style=\"text-align:center;padding:4px;background-color:#F0F0F0;font-weight:bold;\">基本情報</td></tr><tr><th style=\"width:15%;padding:4px;background-color:#F0F0F0;text-align:center;\">フリガナ</th><td style=\"width:35%;padding:4px;\"></td></tr><tr><th style=\"padding:4px;background-color:#F0F0F0;text-align:center;\">氏名</th><td style=\"padding:4px;\"></td></tr><tr><th style=\"padding:4px;background-color:#F0F0F0;text-align:center;\">生年月日</th><td style=\"padding:4px;\"></td></tr><tr><th style=\"padding:4px;background-color:#F0F0F0;text-align:center;\">性別</th><td style=\"padding:4px;\">男・女</td></tr><tr><th style=\"padding:4px;background-color:#F0F0F0;text-align:center;\">年齢</th><td style=\"padding:4px;\">歳</td></tr><tr><th style=\"padding:4px;background-color:#F0F0F0;text-align:center;\">健診年月日</th><td style=\"padding:4px;\"></td></tr><tr><td colspan=\"2\" style=\"text-align:center;padding:4px;background-color:#F0F0F0;font-weight:bold;\">身体測定</td></tr><tr><th style=\"padding:4px;background-color:#F0F0F0;text-align:center;\">身長(cm)</th><td style=\"padding:4px;\"></td></tr><tr><th style=\"padding:4px;background-color:#F0F0F0;text-align:center;\">体重(kg)</th><td style=\"padding:4px;\"></td></tr><tr><th style=\"padding:4px;background-color:#F0F0F0;text-align:center;\">BMI</th><td style=\"padding:4px;\"></td></tr><tr><th style=\"padding:4px;background-color:#F0F0F0;text-align:center;\">腹囲(cm)</th><td style=\"padding:4px;\"></td></tr><tr><td colspan=\"2\" style=\"text-align:center;padding:4px;background-color:#F0F0F0;font-weight:bold;\">生理学的検査</td></tr><tr><th style=\"padding:4px;background-color:#F0F0F0;text-align:center;\">血圧(mmHg)</th><td style=\"padding:4px;\"></td></tr><tr><th style=\"padding:4px;background-color:#F0F0F0;text-align:center;\">視力</th><td style=\"padding:4px;\">右:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;左:</td></tr><tr><th style=\"padding:4px;background-color:#F0F0F0;text-align:center;\">聴力</th><td style=\"padding:4px;\">右:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;左:</td></tr><tr><td colspan=\"2\" style=\"text-align:center;padding:4px;background-color:#F0F0F0;font-weight:bold;\">血液検査</td></tr><tr><th style=\"padding:4px;background-color:#F0F0F0;text-align:center;\">血色素量(g/dl)</th><td style=\"padding:4px;\"></td></tr><tr><th style=\"padding:4px;background-color:#F0F0F0;text-align:center;\">赤血球数(万/mm³)</th><td style=\"padding:4px;\"></td></tr><tr><th style=\"padding:4px;background-color:#F0F0F0;text-align:center;\">GOT(IU/l)</th><td style=\"padding:4px;\"></td></tr><tr><th style=\"padding:4px;background-color:#F0F0F0;text-align:center;\">GPT(IU/l)</th><td style=\"padding:4px;\"></td></tr><tr><th style=\"padding:4px;background-color:#F0F0F0;text-align:center;\">γ-GTP(IU/l)</th><td style=\"padding:4px;\"></td></tr><tr><th style=\"padding:4px;background-color:#F0F0F0;text-align:center;\">LDLコレステロール(mg/dl)</th><td style=\"padding:4px;\"></td></tr><tr><th style=\"padding:4px;background-color:#F0F0F0;text-align:center;\">HDLコレステロール(mg/dl)</th><td style=\"padding:4px;\"></td></tr><tr><th style=\"padding:4px;background-color:#F0F0F0;text-align:center;\">トリグリセライド(mg/dl)</th><td style=\"padding:4px;\"></td></tr><tr><th style=\"padding:4px;background-color:#F0F0F0;text-align:center;\">血糖値(mg/dl)</th><td style=\"padding:4px;\"></td></tr><tr><td colspan=\"2\" style=\"text-align:center;padding:4px;background-color:#F0F0F0;font-weight:bold;\">その他の検査</td></tr><tr><th style=\"padding:4px;background-color:#F0F0F0;text-align:center;\">尿検査</th><td style=\"padding:4px;\">糖:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;蛋白:</td></tr><tr><th style=\"padding:4px;background-color:#F0F0F0;text-align:center;\">心電図検査</th><td style=\"padding:4px;height:40px;vertical-align:top;\"></td></tr><tr><th style=\"padding:4px;background-color:#F0F0F0;text-align:center;\">胸部X線検査</th><td style=\"padding:4px;height:40px;vertical-align:top;\"></td></tr><tr><td colspan=\"2\" style=\"text-align:center;padding:4px;background-color:#F0F0F0;font-weight:bold;\">病歴・症状</td></tr><tr><th style=\"padding:4px;background-color:#F0F0F0;text-align:center;\">業務歴</th><td style=\"padding:4px;height:60px;vertical-align:top;\"></td></tr><tr><th style=\"padding:4px;background-color:#F0F0F0;text-align:center;\">既往歴</th><td style=\"padding:4px;height:60px;vertical-align:top;\"></td></tr><tr><th style=\"padding:4px;background-color:#F0F0F0;text-align:center;\">自覚症状</th><td style=\"padding:4px;height:60px;vertical-align:top;\"></td></tr><tr><th style=\"padding:4px;background-color:#F0F0F0;text-align:center;\">他覚症状</th><td style=\"padding:4px;height:60px;vertical-align:top;\"></td></tr><tr><td colspan=\"2\" style=\"text-align:center;padding:4px;background-color:#F0F0F0;font-weight:bold;\">医師の所見</td></tr><tr><th style=\"padding:4px;background-color:#F0F0F0;text-align:center;\">医師の診断</th><td style=\"padding:4px;height:80px;vertical-align:top;\"></td></tr><tr><th style=\"padding:4px;background-color:#F0F0F0;text-align:center;\">健康診断を実施した医師名</th><td style=\"padding:4px;\"></td></tr><tr><th style=\"padding:4px;background-color:#F0F0F0;text-align:center;\">意見を述べた医師名</th><td style=\"padding:4px;\"></td></tr><tr><th style=\"padding:4px;background-color:#F0F0F0;text-align:center;\">備考</th><td style=\"padding:4px;height:40px;vertical-align:top;\"></td></tr> </tbody></table><br><div style=\"text-align:right;\">発行日:________年____月____日</div>`, }, ], templateIndex: 0, height: 500, width: 800 } ); const templateCmd = new InputMan.GcComboBox( document.getElementById("setTemplate"), { items: ["診断書(簡易)", "診断書(表形式)", "健康診断書"], isEditable: false, }, ); templateCmd.setSelectedIndex(0); templateCmd.addEventListener( InputMan.GcComboBoxEvent.SelectedChanged, (e) => { diagnosisEditor.execCommand( InputMan.GcRichTextEditorCommand.SelectAll); diagnosisEditor.execCommand( InputMan.GcRichTextEditorCommand.Delete); diagnosisEditor.execCommand( InputMan.GcRichTextEditorCommand.Template, e.selectedIndex ); } ); let data = getChartData(); // 症状別累計データの作成 let diagnosisTotalData = {}; data.filter(item => item.type === '診断別').forEach(item => { if (!diagnosisTotalData[item.diagnosis]) { diagnosisTotalData[item.diagnosis] = 0; } diagnosisTotalData[item.diagnosis] += item.count; }); // 月別総患者数データのフィルタリング let monthlyData = data.filter(item => item.type === '総患者数'); // 診断別データの整理 let diagnosisDataByMonth = {}; data.filter(item => item.type === '診断別').forEach(item => { if (!diagnosisDataByMonth[item.month]) { diagnosisDataByMonth[item.month] = []; } diagnosisDataByMonth[item.month].push({ diagnosis: item.diagnosis, count: item.count }); }); let barChart = new chart.FlexChart('#chart', { header: '2024年度 入院者数(月別)', legend: { position: chart.Position.None }, bindingX: 'month', series: [{ binding: 'total', name: '入院者数' }], selectionMode: chart.SelectionMode.Point, itemsSource: monthlyData, selectionChanged: function (sender, args) { let selIndex = sender._selectionIndex; if (selIndex == null || selIndex == -1) { pieChart.itemsSource = []; pieChart.header = '月を選択してください'; } else { let selectedMonth = monthlyData[selIndex].month; let diagnosisData = diagnosisDataByMonth[selectedMonth] || []; pieChart.itemsSource = diagnosisData; pieChart.header = ' 2024年度 ' + (selectedMonth) + ' 症状別患者数(人)'; } } }); // let pieChart = new chart.FlexPie('#pie', { header: '2024年度 1月 症状別患者数(人)', legend: { position: chart.Position.Bottom }, palette: getChartPalette(), selectionMode: chart.SelectionMode.Point, bindingName: 'diagnosis', binding: 'count', itemsSource: diagnosisDataByMonth[monthlyData[0].month], dataLabel: { content: function (ht) { let sum = ht.chart.itemsSource.map(c => c.count).reduce((sum, cur) => sum + cur, 0); let percentage = sum > 0 ? (ht.value / sum * 100).toFixed(1) : 0; return `${ht.value}人 (${percentage}%)`; }, position: 3 }, }); // 折れ線グラフ用データの取得 let diagnosisLineData = getLineChartData(); let linechart = new chart.FlexChart('#linechart', { header: '2024年度 症状別累計推移', legend: { position: chart.Position.Bottom }, chartType: chart.ChartType.Line, bindingX: 'month', series: [ { binding: '肺炎', name: '肺炎' }, { binding: 'インフルエンザ', name: 'インフルエンザ' }, { binding: '骨折', name: '骨折' }, { binding: '糖尿病', name: '糖尿病' }, { binding: '腎不全', name: '腎不全' }, { binding: '悪性新生物', name: '悪性新生物' }, { binding: '心疾患', name: '心疾患' }, { binding: '脳卒中', name: '脳卒中' }, { binding: '認知症', name: '認知症' }, { binding: '骨粗鬆症', name: '骨粗鬆症' }, { binding: '関節リウマチ', name: '関節リウマチ' }, { binding: '慢性閉塞性肺疾患', name: '慢性閉塞性肺疾患' }, { binding: '喘息', name: '喘息' }, ], axisY: { title: '累計患者数(人)' }, itemsSource: diagnosisLineData, palette: getChartPalette() }); const gcDateTime1 = new InputMan.GcDateTime(document.getElementById('gcDateTime1'), { showDropDownButton: true, displayFormatPattern: 'yyy/MM/dd HH:mm', formatPattern: 'yyy/MM/dd HH:mm', //翌日以降 value: new Date(new Date().setDate(new Date().getDate() + 1)), minDate: new Date(new Date().setDate(new Date().getDate() + 1)), }); const gcComboBox1 = new InputMan.GcComboBox(document.getElementById('gcComboBox1'), { items: getPatientName(), autoFilter: InputMan.AutoFilter.Contains, }); let reservationData = getreservationData(); // カスタム編集動作を持つグリッドを作成 var theGrid = new wjGrid.FlexGrid('#theGrid', { isReadOnly: true, selectionMode: 'Row', itemsSource: reservationData, columns: [ { binding: 'id', header: '予約 ID', width: 120, align: 'center' }, { binding: 'patientName', header: '患者名', width: 150, align: 'center' }, { binding: 'date', header: '予約日時', format: 'yyyy/MM/dd HH:mm', width: 150, align: 'center' }, { binding: 'state', header: '診察状況', width: 200, cellTemplate: '<span class="badge bg-secondary bg-${text}">${text}</span>', align: 'center' }, ], }); // theGrid.rowHeaders.columns.insert(0, new wjGrid.Column()); theGrid.formatItem.addHandler(function (s, e) { if (e.panel == s.rowHeaders && e.col == 0) { //診察状況が診察済みのセルは追加しない if (s.rows[e.row].dataItem.state === '診察済み') { e.cell.innerHTML = ''; return; } e.cell.innerHTML = '<span class="wj-glyph-pencil"></span>'; } }); theGrid.formatItem.addHandler(function (s, e) { if (e.panel == s.rowHeaders && e.col == 1) { e.cell.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi " viewBox="0 0 16 16"><path d="M5.5 5.5A.5.5 0 0 1 6 6v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5m2.5 0a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5m3 .5a.5.5 0 0 0-1 0v6a.5.5 0 0 0 1 0z"/> <path d="M14.5 3a1 1 0 0 1-1 1H13v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V4h-.5a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1H6a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1h3.5a1 1 0 0 1 1 1zM4.118 4 4 4.059V13a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V4.059L11.882 4zM2.5 3h11V2h-11z"/></svg>'; } }); document.getElementById('reservationButton').addEventListener('click', function () { //gcComboBox1とgcDateTime1の値をtheGridのitemsSourceに追加 if (gcComboBox1.text === '' || !gcDateTime1.value) { alert('患者名と予約日時を入力してください。'); return; } let newId = theGrid.itemsSource.length > 0 ? Math.max(...theGrid.itemsSource.map(item => item.id.split('-')[2])) + 1 : 1; let item = { id: "IMWJ-Res-" + newId, patientName: gcComboBox1.text, date: gcDateTime1.value, state: '未診察' }; theGrid.collectionView.addNew(item); theGrid.collectionView.commitNew(); //入力欄をクリア gcComboBox1.text = ''; gcDateTime1.value = new Date(new Date().setDate(new Date().getDate() + 1)); alert('予約が完了しました。予約ID: ' + item.id); }) // // 新しいアイテムを作成 // // ボタンクリックの処理 theGrid.addEventListener(theGrid.hostElement, 'click', function (e) { var ht = theGrid.hitTest(e); //行ヘッダーかつ編集ボタンがクリックされた場合 if (ht.panel == theGrid.rowHeaders && ht.col == 0 && theGrid.rows[ht.row].dataItem.state !== '診察済み') { // // フォームを準備 var item = theGrid.rows[ht.row].dataItem; formControls.itemId.textContent = item.id; formControls.patientName.text = item.patientName; formControls.date.value = item.date; // // フォームを表示 formControls.popup.show(true, function (e) { if (e.dialogResult == 'wj-hide-ok') { // // ユーザーがOKボタンを押した場合、変更を確定 theGrid.collectionView.editItem(item); item.patientName = formControls.patientName.text; item.date = formControls.date.value; theGrid.collectionView.commitEdit(); confirm('予約 ID ' + item.id + ' を更新しました。'); } else { // // ユーザーがキャンセルボタンを押した場合、編集をキャンセル theGrid.collectionView.cancelEdit(); } // // グリッドにフォーカスを戻す theGrid.focus(); }); } else if (ht.panel == theGrid.rowHeaders && ht.col == 1) { // 削除フォームを準備 var item = theGrid.rows[ht.row].dataItem; deleteControls.itemId.textContent = item.id; // // 削除確認を表示 deleteControls.popup.show(true, function (e) { if (e.dialogResult == 'wj-hide-remove') { // // ユーザーがOKボタンを押した場合、アイテムを削除 theGrid.collectionView.remove(item); confirm('予約 ID ' + item.id + ' を削除しました。'); } // // グリッドにフォーカスを戻す theGrid.focus(); }); } }); let formControls = { popup: new wjInput.Popup('#popup'), itemId: document.getElementById('item-id'), patientName: new InputMan.GcComboBox(document.getElementById('patientName'), { items: getPatientName(), }), date: new InputMan.GcDateTime(document.getElementById('date'), { showDropDownButton: true, displayFormatPattern: 'yyy/MM/dd HH:mm', formatPattern: 'yyy/MM/dd HH:mm', value: new Date(new Date().setDate(new Date().getDate() + 1)), minDate: new Date(new Date().setDate(new Date().getDate() + 1)), }) }; let deleteControls = { popup: new wjInput.Popup('#popup2'), itemId: document.getElementById('item-id2') };
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>実用例 - 患者データ管理</title> <!-- SystemJS --> <script src="node_modules/systemjs/dist/system.src.js"></script> <script src="systemjs.config.js"></script> <script> window.onload = function () { System.import('./src/app'); } </script> </head> <div class="container-fluid"> <div id="theTabPanel" class="custom-tab"> <div> <a>診察予約</a> <div> <div class="flexbox"> <div id="container1"> 患者名: <select id="gcComboBox1"></select> 予約日: <input id="gcDateTime1" /> <button id="reservationButton">予約</button> </div> </div> <main class="container-fluid"> <div id="theGrid"> </div> <!-- the popup editor --> <div id="popup" class="modal-content"> <div class="modal-header"> <button type="button" tabindex="-1" class="close wj-hide"> &times; </button> <h4 class="modal-title">ID <span id="item-id"></span>の編集</h4> </div> <div class="modal-body"> <div class="wj-labeled-input"> <select id="patientName"></select> <label for="patientName">患者名</label> </div> <div class="wj-labeled-input"> <input id="date" /> <label for="date">受診日</label> </div> <div class="modal-footer"> <button type="button" class="btn btn-primary wj-hide-ok">OK</button> <button type="button" class="btn btn-default wj-hide">キャンセル</button> </div> </div> </div> <div id="popup2" class="modal-content"> <div class="modal-header"> <button type="button" tabindex="-1" class="close wj-hide"> &times; </button> <h4 class="modal-title">ID <span id="item-id2"></span>の削除</h4> </div> <div class="modal-body"> <div class="modal-footer2"> <button type="button" class="btn btn-danger wj-hide-remove">削除</button> <button type="button" class="btn btn-default wj-hide">キャンセル</button> </div> </div> </div> </main> </div> </div> <div> <a>患者情報</a> <div> <div id="patientsGrid"></div> </div> </div> <div> <a>診断書</a> <div> <table class="sample"> <tbody> <tr> <th>診断書:</th> <td> <select id="setTemplate"></select> </td> </tr> </tbody> </table> <textarea id="diagnosisTextArea"></textarea> </div> </div> <div> <a>BMI</a> <div> <div id="bmiSheet"></div> </div> </div> <div> <a>過去データ分析</a> <div> <div> <div class="row"> <div id="linechart"></div> </div> <div class="row"> <div class="col"> <div id="chart"></div> </div> <div class="col"> <div id="pie"></div> </div> </div> </div> </div> </div> </div> <div> <p>このデモサイトではBootstrap Iconsを利用しています。</p> <p>Copyright (c) 2011-2025 The Bootstrap Authors</p> <a href="https://github.com/twbs/bootstrap/blob/main/LICENSE" target="_blank">Bootstrap Iconsのライセンス</a> </div> </div> </body> </html>
.wj-tabpanel { padding: 0 12px; } .wj-tabpane { padding: 12px; } .wj-tabheader:hover { outline: 2px solid rgba(90, 160, 215, .5); } /* custom-headers */ .wj-tabpanel.custom-headers .wj-tabpanes { border: none; } .wj-tabpanel.custom-headers>div>.wj-tabheaders { background: black; color: white; border: none; } .wj-tabpanel.custom-headers .wj-tabheaders .wj-tabheader.wj-state-active { background: white; color: black; } .wj-tabpanel.custom-headers .wj-tabheaders .wj-tabheader:not(.wj-state-active) { font-weight: normal; } .wj-tabpanel.custom-headers .wj-tabheaders .wj-tabheader.wj-state-active:after { display: none; /* hide underline */ } /* tabs on the left */ .wj-tabpanel.tabs-left>div { display: flex; align-items: center; } .wj-tabpanel.tabs-left .wj-tabheaders { display: flex; flex-direction: column; min-width: 8em; border-right: 1px solid #ddd; } .wj-tabpanel.tabs-left .wj-tabheaders .wj-tabheader { text-align: right; } .wj-tabpanel.tabs-left .wj-tabpanes { display: flex; flex-grow: 1; border-top: none; overflow-x: hidden; } /* tabs on the right */ .wj-tabpanel.tabs-right>div { display: flex; align-items: center; } .wj-tabpanel.tabs-right .wj-tabheaders { display: flex; flex-direction: column; min-width: 8em; border-left: 1px solid #ddd; order: 1; } .wj-tabpanel.tabs-right .wj-tabheaders .wj-tabheader { text-align: left; } .wj-tabpanel.tabs-right .wj-tabpanes { display: flex; flex-grow: 1; border-top: none; overflow-x: hidden; order: 0; } /* tabs below */ .wj-tabpanel.tabs-below>div { display: flex; flex-direction: column; align-items: stretch; } .wj-tabpanel.tabs-below .wj-tabheaders { order: 1; /* headers after panes */ } .wj-tabpanel.tabs-below .wj-tabpanes { order: 0; } .wj-tabpanel.tabs-below .wj-tabheaders .wj-tabheader.wj-state-active:after { top: 0; bottom: unset; } .wj-cell.wj-group:not(.wj-state-selected):not(.wj-state-multi-selected) { background-color: white; } .wj-flexgrid { max-height: 450px; } .bg-使用中 { background-color: rgb(48, 83, 240); } .bg-空き { background-color: green; } .bg-診察済み { background-color: rgb(49, 139, 105); } .bg-未診察 { background-color: rgb(214, 46, 186); } .badge { padding: 6px 25px; } .wj-flexsheet { height: 400px; margin: 6px 0; } table.sample { border-collapse: collapse; margin-top: 1rem; } table.sample tr>* { padding: 0.25rem 0.5rem; border: 1px solid #D2D2D2; } table.sample tr>th { text-align: left; background: #F0F0F0; font-weight: normal; } .col { float:left; width: 50%; } .flexbox > div { height: 50px; width: 650px; background-color: #f8f8f8; } #container1{ padding-top: 10px; } .wj-flexgrid { max-height: 400px; margin-bottom: 12px; } .modal-content { width: 480px; height: 480px; } #popup2 { width: 360px; height: 120px; } /* style our custom 'edit buttons' */ .wj-rowheaders .wj-cell .wj-glyph-pencil { opacity: .5; padding-left: 3px; } .wj-rowheaders .wj-cell:hover .wj-glyph-pencil { opacity: 1; color: #cc0000; transform: scale(1.5); transition: all 400ms; } .wj-rowheaders .wj-cell .bi { opacity: .5; transform: scale(.95); padding-top: 3px; } .wj-rowheaders .wj-cell .bi:hover { opacity: 1; color: #cc0000; transform: scale(1.4); transition: all 400ms; } /* wj-labeled-input: adapted from MDL styles */ /* label input container */ .wj-labeled-input { position: relative; font-size: 16px; display: inline-block; box-sizing: border-box; width: 300px; max-width: 100%; margin: 0 20px; padding: 20px 0; } /* Wijmo control in the container */ .wj-labeled-input .wj-control.wj-content { margin: 0; width: 100%; background-color: transparent; border: none; border-bottom: 1px solid rgba(0, 0, 0, .1); } .wj-labeled-input .wj-control.wj-content button { opacity: 0.75; border-color: rgba(0, 0, 0, .1); } .wj-labeled-input .wj-input-group .wj-form-control { float: none; } /* label in the container (must come after the control) */ .wj-labeled-input label { font-size: 16px; top: 24px; bottom: 0; margin: 0; pointer-events: none; position: absolute; display: block; width: 100%; overflow: hidden; white-space: nowrap; text-align: left; color: rgba(0, 0, 0, 0.258824); transition-duration: .2s; transition-timing-function: cubic-bezier(.4, 0, .2, 1); } /* move label out of the way when control is focused or not empty */ .wj-static-labels .wj-labeled-input :not(.wj-state-focused)+label, .wj-labeled-input .wj-state-focused+label, .wj-labeled-input :not(.wj-state-empty)+label { font-size: 12px; top: 4px; color: rgb(63, 81, 181); visibility: visible; } .wj-labeled-input .wj-state-invalid+label { color: #d50000; } /* underline label */ .wj-labeled-input label:after { background-color: rgb(63, 81, 181); bottom: 20px; content: ''; height: 2px; left: 45%; position: absolute; transition-duration: .2s; transition-timing-function: cubic-bezier(.4, 0, .2, 1); visibility: hidden; width: 10px; } /* show underline when focused */ .wj-labeled-input .wj-state-focused+label:after { left: 0; visibility: visible; width: 100%; } .wj-labeled-input .wj-state-invalid+label:after { background-color: #d50000; } /* validation message */ .wj-labeled-input .wj-error { color: #d50000; position: absolute; font-size: 12px; margin-top: 3px; visibility: hidden; display: block; } .wj-labeled-input .wj-control.wj-state-invalid~.wj-error { visibility: visible; } .modal-footer{ padding-top: 200px; } .modal-footer2{ text-align: right; } #theGrid{ margin-top: 5px; } .wj-flexsheet .wj-tabholder div.wj-new-sheet { display: none }
import * as wjCore from '@mescius/wijmo'; import { InputDate, ComboBox, InputMask } from '@mescius/wijmo.input'; import '@mescius/wijmo.cultures/wijmo.culture.ja' export function getpaintData() { var patients = [{ name: 'A棟', checks: [{ name: '101 病室', patientInfomation: [ { name: 'ベッド1', status: '使用中', patientName: '佐藤 太郎', diagnosis: '肺炎', height: 188, weight: 95, age: 65, bloodPressure: '120/80', hospitalizationDay: new Date(2025, 0, 1), doctorAssigned: '仙台 四郎' }, { name: 'ベッド2', status: '使用中', patientName: '斎藤 五郎', diagnosis: 'インフルエンザ', height: 172, weight: 67, age: 42, bloodPressure: '115/75', hospitalizationDay: new Date(2025, 10, 21), doctorAssigned: '仙台 四郎' }, { name: 'ベッド3', status: '使用中', patientName: '鈴木 三郎', diagnosis: '肺炎', height: 181, weight: 72, age: 52, bloodPressure: '118/76', hospitalizationDay: new Date(2025, 2, 3), doctorAssigned: '仙台 四郎' }, { name: 'ベッド4', status: '空き', patientName: '-', diagnosis: '-', height: '-', weight: '-', age: '-', bloodPressure: '-', hospitalizationDay: '-', doctorAssigned: '-' }, ] }, { name: '102 病室', patientInfomation: [ { name: 'ベッド1', status: '使用中', patientName: '高橋 太郎', diagnosis: '骨折', height: 167, weight: 100, age: 34, bloodPressure: '110/70', hospitalizationDay: new Date(2025, 5, 15), doctorAssigned: '富沢 二郎' }, { name: 'ベッド2', status: '空き', patientName: '-', diagnosis: '-', height: '-', weight: '-', age: '-', bloodPressure: '-', hospitalizationDay: '-', doctorAssigned: '-' }, { name: 'ベッド3', status: '空き', patientName: '-', diagnosis: '-', height: '-', weight: '-', age: '-', bloodPressure: '-', hospitalizationDay: '-', doctorAssigned: '-' }, { name: 'ベッド4', status: '空き', patientName: '-', diagnosis: '-', height: '-', weight: '-', age: '-', bloodPressure: '-', hospitalizationDay: '-', doctorAssigned: '-' }, ] }, { name: '201 病室', patientInfomation: [ { name: 'ベッド1', status: '使用中', patientName: '田中 太郎', diagnosis: '糖尿病', height: 173, weight: 88, age: 45, bloodPressure: '130/85', hospitalizationDay: new Date(2025, 0, 1), doctorAssigned: '紫山 一郎' }, { name: 'ベッド2', status: '使用中', patientName: '佐藤 次郎', diagnosis: '糖尿病', height: 179, weight: 95, age: 37, bloodPressure: '125/80', hospitalizationDay: new Date(2025, 10, 21), doctorAssigned: '紫山 一郎' }, { name: 'ベッド3', status: '使用中', patientName: '鈴本 三郎', diagnosis: '腎不全', height: 186, weight: 69, age: 75, bloodPressure: '120/75', hospitalizationDay: new Date(2025, 2, 3), doctorAssigned: '紫山 一郎' }, { name: 'ベッド4', status: '使用中', patientName: '田中 四郎', diagnosis: '腎不全', height: 175, weight: 62, age: 71, bloodPressure: '115/80', hospitalizationDay: new Date(2025, 4, 10), doctorAssigned: '紫山 一郎' }, ] }] }, { name: 'B 棟', checks: [{ name: '101 病室', patientInfomation: [ { name: 'ベッド1', status: '空き', patientName: '-', diagnosis: '-', height: '-', weight: '-', age: '-', bloodPressure: '-', hospitalizationDay: '-', doctorAssigned: '-' }, { name: 'ベッド2', status: '使用中', patientName: '坂本 次郎', diagnosis: '悪性新生物', height: 168, weight: 50, age: 56, bloodPressure: '125/80', hospitalizationDay: new Date(2025, 10, 21), doctorAssigned: '長町 みなみ' }, { name: 'ベッド3', status: '空き', patientName: '-', diagnosis: '-', height: '-', weight: '-', age: '-', bloodPressure: '-', hospitalizationDay: '-', doctorAssigned: '-' }, { name: 'ベッド4', status: '使用中', patientName: '田中 五郎', diagnosis: '悪性新生物', height: 191, weight: 53, age: 63, bloodPressure: '130/85', hospitalizationDay: new Date(2025, 4, 10), doctorAssigned: '長町 みなみ' }, ] }, { name: '102 病室', patientInfomation: [ { name: 'ベッド1', status: '使用中', patientName: '鈴木 六郎', diagnosis: '心疾患', height: 184, weight: 71, age: 47, bloodPressure: '120/80', hospitalizationDay: new Date(2025, 2, 3), doctorAssigned: '泉 花子' }, { name: 'ベッド2', status: '使用中', patientName: '高橋 七郎', diagnosis: '心疾患', height: 169, weight: 83, age: 29, bloodPressure: '115/75', hospitalizationDay: new Date(2025, 5, 15), doctorAssigned: '泉 花子' }, { name: 'ベッド3', status: '使用中', patientName: '田中 八郎', diagnosis: '脳卒中', height: 177, weight: 64, age: 78, bloodPressure: '120/80', hospitalizationDay: new Date(2025, 4, 10), doctorAssigned: '黒松 太郎' }, { name: 'ベッド4', status: '空き', patientName: '-', diagnosis: '-', height: '-', weight: '-', age: '-', bloodPressure: '-', hospitalizationDay: '-', doctorAssigned: '-' }, ] }] }, { name: 'C 棟', checks: [{ name: '101 病室', patientInfomation: [ { name: 'ベッド1', status: '使用中', patientName: '中田 一郎', diagnosis: '脳卒中', height: 170, weight: 60, age: 80, bloodPressure: '130/85', hospitalizationDay: new Date(2025, 0, 1), doctorAssigned: '台原 ひとみ' }, { name: 'ベッド2', status: '使用中', patientName: '太子堂 二郎', diagnosis: '認知症', height: 165, weight: 55, age: 82, bloodPressure: '125/80', hospitalizationDay: new Date(2025, 10, 21), doctorAssigned: '台原 ひとみ' }, { name: 'ベッド3', status: '空き', patientName: '-', diagnosis: '-', height: '-', weight: '-', age: '-', bloodPressure: '-', hospitalizationDay: '-', doctorAssigned: '-' }, { name: 'ベッド4', status: '空き', patientName: '-', diagnosis: '-', height: '-', weight: '-', age: '-', bloodPressure: '-', hospitalizationDay: '-', doctorAssigned: '-' }, ] }, { name: '102 病室', patientInfomation: [ { name: 'ベッド1', status: '使用中', patientName: '三田村 三郎', diagnosis: '認知症', height: 180, weight: 70, age: 77, bloodPressure: '120/80', hospitalizationDay: new Date(2025, 2, 3), doctorAssigned: '青葉 さくら' }, { name: 'ベッド2', status: '空き', patientName: '-', diagnosis: '-', height: '-', weight: '-', age: '-', bloodPressure: '-', hospitalizationDay: '-', doctorAssigned: '-' }, { name: 'ベッド3', status: '空き', patientName: '-', diagnosis: '-', height: '-', weight: '-', age: '-', bloodPressure: '-', hospitalizationDay: '-', doctorAssigned: '-' }, { name: 'ベッド4', status: '空き', patientName: '-', diagnosis: '-', height: '-', weight: '-', age: '-', bloodPressure: '-', hospitalizationDay: '-', doctorAssigned: '-' }, ], }, { name: '201 病室', patientInfomation: [ { name: 'ベッド1', status: '使用中', patientName: '山田 四郎', diagnosis: '骨粗鬆症', height: 175, weight: 65, age: 68, bloodPressure: '130/85', hospitalizationDay: new Date(2025, 0, 1), doctorAssigned: '国見 太一' }, { name: 'ベッド2', status: '使用中', patientName: '田村 五郎', diagnosis: '骨粗鬆症', height: 178, weight: 70, age: 72, bloodPressure: '125/80', hospitalizationDay: new Date(2025, 10, 21), doctorAssigned: '国見 太一' }, { name: 'ベッド3', status: '使用中', patientName: '鈴木 六郎', diagnosis: '関節リウマチ', height: 172, weight: 60, age: 66, bloodPressure: '120/75', hospitalizationDay: new Date(2025, 2, 3), doctorAssigned: '国見 太一' }, { name: 'ベッド4', status: '空き', patientName: '-', diagnosis: '-', height: '-', weight: '-', age: '-', bloodPressure: '-', hospitalizationDay: '-', doctorAssigned: '-' }, ], }] }, { name: 'D 棟', checks: [{ name: '101 病室', patientInfomation: [ { name: 'ベッド1', status: '使用中', patientName: '佐々木 一郎', diagnosis: '慢性閉塞性肺疾患', height: 185, weight: 90, age: 58, bloodPressure: '140/90', hospitalizationDay: new Date(2025, 0, 1), doctorAssigned: '八木山 花子' }, { name: 'ベッド2', status: '使用中', patientName: '高橋 二郎', diagnosis: '喘息', height: 170, weight: 75, age: 40, bloodPressure: '135/85', hospitalizationDay: new Date(2025, 10, 21), doctorAssigned: '八木山 花子' }, { name: 'ベッド3', status: '空き', patientName: '-', diagnosis: '-', height: '-', weight: '-', age: '-', bloodPressure: '-', hospitalizationDay: '-', doctorAssigned: '-' }, { name: 'ベッド4', status: '空き', patientName: '-', diagnosis: '-', height: '-', weight: '-', age: '-', bloodPressure: '-', hospitalizationDay: '-', doctorAssigned: '-' }, ] }, { name: '102 病室', patientInfomation: [ { name: 'ベッド1', status: '使用中', patientName: '田中 三郎', diagnosis: '喘息', height: 160, weight: 68, age: 35, bloodPressure: '130/80', hospitalizationDay: new Date(2025, 2, 3), doctorAssigned: '広瀬 太一' }, { name: 'ベッド2', status: '空き', patientName: '-', diagnosis: '-', height: '-', weight: '-', age: '-', bloodPressure: '-', hospitalizationDay: '-', doctorAssigned: '-' }, { name: 'ベッド3', status: '空き', patientName: '-', diagnosis: '-', height: '-', weight: '-', age: '-', bloodPressure: '-', hospitalizationDay: '-', doctorAssigned: '-' }, { name: 'ベッド4', status: '空き', patientName: '-', diagnosis: '-', height: '-', weight: '-', age: '-', bloodPressure: '-', hospitalizationDay: '-', doctorAssigned: '-' }, ], }, { name: '201 病室', patientInfomation: [ { name: 'ベッド1', status: '使用中', patientName: '山本 四郎', diagnosis: '慢性閉塞性肺疾患', height: 174, weight: 80, age: 60, bloodPressure: '140/90', hospitalizationDay: new Date(2025, 0, 1), doctorAssigned: '仙台 太郎' }, { name: 'ベッド2', status: '使用中', patientName: '中村 五郎', diagnosis: '肺結核', height: 182, weight: 78, age: 55, bloodPressure: '135/85', hospitalizationDay: new Date(2025, 10, 21), doctorAssigned: '仙台 太郎' }, { name: 'ベッド3', status: '使用中', patientName: '小林 六郎', diagnosis: '肺結核', height: 176, weight: 72, age: 50, bloodPressure: '130/80', hospitalizationDay: new Date(2025, 2, 3), doctorAssigned: '仙台 太郎' }, { name: 'ベッド4', status: '空き', patientName: '-', diagnosis: '-', height: '-', weight: '-', age: '-', bloodPressure: '-', hospitalizationDay: '-', doctorAssigned: '-' }, ], }] }]; return patients; } export function getpaintInformation(patients) { let patientsData = []; patients.forEach(building => { building.checks.forEach(room => { room.patientInfomation.forEach(bed => { if (bed.status === '使用中') { patientsData.push({ 患者名: bed.patientName, 年齢: bed.age, 診断名: bed.diagnosis, 身長: bed.height, 体重: bed.weight, BMI: 0, BMI判定: '', 血圧: bed.bloodPressure, 担当医: bed.doctorAssigned }); } }); }); }); return patientsData; } export function getChartData() { let chartData = []; // 月別患者数データ const monthlyData = [ { month: '1月', total: 50, data: { '肺炎': 5, 'インフルエンザ': 10, '骨折': 3, '糖尿病': 8, '腎不全': 4, '悪性新生物': 6, '心疾患': 5, '脳卒中': 3, '認知症': 2, '骨粗鬆症': 2, '関節リウマチ': 1, '慢性閉塞性肺疾患': 1 } }, { month: '2月', total: 46, data: { '肺炎': 8, 'インフルエンザ': 12, '骨折': 2, '糖尿病': 6, '腎不全': 3, '悪性新生物': 4, '心疾患': 4, '脳卒中': 2, '認知症': 2, '骨粗鬆症': 1, '関節リウマチ': 1, '喘息': 1 } }, { month: '3月', total: 39, data: { '肺炎': 4, 'インフルエンザ': 6, '骨折': 4, '糖尿病': 7, '腎不全': 3, '悪性新生物': 5, '心疾患': 3, '脳卒中': 2, '認知症': 2, '骨粗鬆症': 1, '関節リウマチ': 1, '喘息': 1 } }, { month: '4月', total: 42, data: { '肺炎': 3, 'インフルエンザ': 2, '骨折': 5, '糖尿病': 9, '腎不全': 4, '悪性新生物': 6, '心疾患': 4, '脳卒中': 3, '認知症': 2, '骨粗鬆症': 2, '関節リウマチ': 1, '喘息': 1 } }, { month: '5月', total: 48, data: { '肺炎': 2, 'インフルエンザ': 1, '骨折': 6, '糖尿病': 10, '腎不全': 5, '悪性新生物': 7, '心疾患': 5, '脳卒中': 4, '認知症': 3, '骨粗鬆症': 2, '関節リウマチ': 2, '喘息': 1 } }, { month: '6月', total: 52, data: { '肺炎': 2, 'インフルエンザ': 1, '骨折': 7, '糖尿病': 11, '腎不全': 6, '悪性新生物': 8, '心疾患': 6, '脳卒中': 4, '認知症': 3, '骨粗鬆症': 2, '関節リウマチ': 1, '喘息': 1 } }, { month: '7月', total: 56, data: { '肺炎': 1, 'インフルエンザ': 1, '骨折': 8, '糖尿病': 12, '腎不全': 7, '悪性新生物': 9, '心疾患': 7, '脳卒中': 4, '認知症': 3, '骨粗鬆症': 2, '関節リウマチ': 1, '喘息': 1 } }, { month: '8月', total: 60, data: { '肺炎': 1, 'インフルエンザ': 1, '骨折': 9, '糖尿病': 13, '腎不全': 8, '悪性新生物': 10, '心疾患': 7, '脳卒中': 4, '認知症': 3, '骨粗鬆症': 2, '関節リウマチ': 1, '喘息': 1 } }, { month: '9月', total: 47, data: { '肺炎': 2, 'インフルエンザ': 1, '骨折': 6, '糖尿病': 10, '腎不全': 6, '悪性新生物': 7, '心疾患': 5, '脳卒中': 3, '認知症': 3, '骨粗鬆症': 2, '関節リウマチ': 1, '喘息': 1 } }, { month: '10月', total: 49, data: { '肺炎': 3, 'インフルエンザ': 3, '骨折': 5, '糖尿病': 9, '腎不全': 6, '悪性新生物': 8, '心疾患': 5, '脳卒中': 3, '認知症': 3, '骨粗鬆症': 2, '関節リウマチ': 1, '喘息': 1 } }, { month: '11月', total: 53, data: { '肺炎': 6, 'インフルエンザ': 8, '骨折': 4, '糖尿病': 8, '腎不全': 5, '悪性新生物': 7, '心疾患': 5, '脳卒中': 3, '認知症': 3, '骨粗鬆症': 2, '関節リウマチ': 1, '喘息': 1 } }, { month: '12月', total: 60, data: { '肺炎': 9, 'インフルエンザ': 15, '骨折': 3, '糖尿病': 7, '腎不全': 4, '悪性新生物': 6, '心疾患': 5, '脳卒中': 3, '認知症': 3, '骨粗鬆症': 2, '関節リウマチ': 2, '喘息': 1 } } ]; // チャート用データの整形 monthlyData.forEach(monthData => { // 月別総患者数 chartData.push({ month: monthData.month, total: monthData.total, type: '総患者数' }); // 診断別患者数 Object.keys(monthData.data).forEach(diagnosis => { chartData.push({ month: monthData.month, count: monthData.data[diagnosis], diagnosis: diagnosis, type: '診断別' }); }); }); return chartData; } export function getChartPalette() { // 12色のカラーパレットを定義 const twelveColors = [ '#1f77b4', // 青 '#ff7f0e', // オレンジ '#2ca02c', // 緑 '#d62728', // 赤 '#9467bd', // 紫 '#8c564b', // 茶 '#e377c2', // ピンク '#7f7f7f', // グレー '#bcbd22', // 黄緑 '#17becf', // シアン '#aec7e8', // ライトブルー '#ffbb78' // ライトオレンジ ]; return twelveColors; } export function getLineChartData() { let data = getChartData(); // 診断名の順序を定義 const diagnosisOrder = ['肺炎', 'インフルエンザ', '骨折', '糖尿病', '腎不全', '悪性新生物', '心疾患', '脳卒中', '認知症', '骨粗鬆症', '関節リウマチ', '慢性閉塞性肺疾患', '喘息']; // 症状別累計データの作成 let diagnosisTotalData = {}; diagnosisOrder.forEach(diagnosis => { diagnosisTotalData[diagnosis] = 0; }); data.filter(item => item.type === '診断別').forEach(item => { if (diagnosisTotalData.hasOwnProperty(item.diagnosis)) { diagnosisTotalData[item.diagnosis] += item.count; } }); // 診断別データの整理 let diagnosisDataByMonth = {}; data.filter(item => item.type === '診断別').forEach(item => { if (!diagnosisDataByMonth[item.month]) { diagnosisDataByMonth[item.month] = []; } diagnosisDataByMonth[item.month].push({ diagnosis: item.diagnosis, count: item.count }); }); // 症状別月別推移データの作成(折れ線グラフ用 - 累計値) let diagnosisLineData = []; let months = ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月']; // 累計値を管理するオブジェクト let cumulativeData = {}; diagnosisOrder.forEach(diagnosis => { cumulativeData[diagnosis] = 0; }); // 月ごとのデータを作成(累計値) months.forEach(month => { let monthObj = { month: month }; // その月の診断別データを取得 let monthDiagnosisData = diagnosisDataByMonth[month] || []; // 各診断の患者数を累計に追加 monthDiagnosisData.forEach(item => { if (cumulativeData.hasOwnProperty(item.diagnosis)) { cumulativeData[item.diagnosis] += item.count; } }); // 累計値を月オブジェクトに設定(定義された順序で) diagnosisOrder.forEach(diagnosis => { monthObj[diagnosis] = cumulativeData[diagnosis]; }); diagnosisLineData.push(monthObj); }); return diagnosisLineData; } export function getPatientName() { let patients = getpaintData(); let patientNames = []; patients.forEach(building => { building.checks.forEach(room => { room.patientInfomation.forEach(bed => { if (bed.status === '使用中' && bed.patientName !== '-') { patientNames.push(bed.patientName); } }); }); }); return patientNames; } export function getreservationData(){ let data = []; let patientNames = getPatientName(); for (let i = 1; i <= 4; i++) { data.push({ id: 'IMWJ-Res-'+i, patientName: patientNames[i - 1], date: wjCore.DateTime.addDays(new Date(), -i * 5), state:'診察済み' }); } return data; }
[gcim-control-appearance="modern"] table.form > tbody > tr > th { text-align: left; font-weight: normal; }
System.config({ transpiler: 'plugin-babel', babelOptions: { es2015: true }, meta: { '*.css': { loader: 'css' } }, paths: { // paths serve as alias 'npm:': 'node_modules/' }, // map tells the System loader where to look for things map: { '@mescius/inputman': 'npm:@mescius/inputman/index.js', '@mescius/inputman/CSS': 'npm:@mescius/inputman/CSS', '@mescius/inputman.richtexteditor': 'npm:@mescius/inputman.richtexteditor/index.js', "@mescius/inputman.richtexteditor/CSS": "npm:@mescius/inputman.richtexteditor/CSS", '@mescius/inputman.richtexteditor/JS/plugins/advlist': 'npm:@mescius/inputman.richtexteditor/JS/plugins/advlist/plugin.js', '@mescius/inputman.richtexteditor/JS/plugins/all': 'npm:@mescius/inputman.richtexteditor/JS/plugins/all/plugin.js', '@mescius/inputman.richtexteditor/JS/plugins/autosave': 'npm:@mescius/inputman.richtexteditor/JS/plugins/autosave/plugin.js', '@mescius/inputman.richtexteditor/JS/plugins/charmap': 'npm:@mescius/inputman.richtexteditor/JS/plugins/charmap/plugin.js', '@mescius/inputman.richtexteditor/JS/plugins/directionality': 'npm:@mescius/inputman.richtexteditor/JS/plugins/directionality/plugin.js', '@mescius/inputman.richtexteditor/JS/plugins/emoticons': 'npm:@mescius/inputman.richtexteditor/JS/plugins/emoticons/plugin.js', '@mescius/inputman.richtexteditor/JS/plugins/fullscreen': 'npm:@mescius/inputman.richtexteditor/JS/plugins/fullscreen/plugin.js', '@mescius/inputman.richtexteditor/JS/plugins/htmlcode': 'npm:@mescius/inputman.richtexteditor/JS/plugins/htmlcode/plugin.js', '@mescius/inputman.richtexteditor/JS/plugins/image': 'npm:@mescius/inputman.richtexteditor/JS/plugins/image/plugin.js', '@mescius/inputman.richtexteditor/JS/plugins/link': 'npm:@mescius/inputman.richtexteditor/JS/plugins/link/plugin.js', '@mescius/inputman.richtexteditor/JS/plugins/lists': 'npm:@mescius/inputman.richtexteditor/JS/plugins/lists/plugin.js', '@mescius/inputman.richtexteditor/JS/plugins/media': 'npm:@mescius/inputman.richtexteditor/JS/plugins/media/plugin.js', '@mescius/inputman.richtexteditor/JS/plugins/pagebreak': 'npm:@mescius/inputman.richtexteditor/JS/plugins/pagebreak/plugin.js', '@mescius/inputman.richtexteditor/JS/plugins/preview': 'npm:@mescius/inputman.richtexteditor/JS/plugins/preview/plugin.js', '@mescius/inputman.richtexteditor/JS/plugins/save': 'npm:@mescius/inputman.richtexteditor/JS/plugins/save/plugin.js', '@mescius/inputman.richtexteditor/JS/plugins/searchreplace': 'npm:@mescius/inputman.richtexteditor/JS/plugins/searchreplace/plugin.js', '@mescius/inputman.richtexteditor/JS/plugins/table': 'npm:@mescius/inputman.richtexteditor/JS/plugins/table/plugin.js', '@mescius/inputman.richtexteditor/JS/plugins/template': 'npm:@mescius/inputman.richtexteditor/JS/plugins/template/plugin.js', '@mescius/inputman.richtexteditor/JS/plugins/wordcount': 'npm:@mescius/inputman.richtexteditor/JS/plugins/wordcount/plugin.js', '@mescius/inputman.comment': 'npm:@mescius/inputman.comment/index.js', '@mescius/inputman.comment/CSS': 'npm:@mescius/inputman.comment/CSS', 'jszip': 'npm:jszip/dist/jszip.js', '@mescius/wijmo': 'npm:@mescius/wijmo/index.js', '@mescius/wijmo.input': 'npm:@mescius/wijmo.input/index.js', '@mescius/wijmo.styles': 'npm:@mescius/wijmo.styles', '@mescius/wijmo.cultures': 'npm:@mescius/wijmo.cultures', '@mescius/wijmo.chart': 'npm:@mescius/wijmo.chart/index.js', '@mescius/wijmo.chart.analytics': 'npm:@mescius/wijmo.chart.analytics/index.js', '@mescius/wijmo.chart.animation': 'npm:@mescius/wijmo.chart.animation/index.js', '@mescius/wijmo.chart.annotation': 'npm:@mescius/wijmo.chart.annotation/index.js', '@mescius/wijmo.chart.finance': 'npm:@mescius/wijmo.chart.finance/index.js', '@mescius/wijmo.chart.finance.analytics': 'npm:@mescius/wijmo.chart.finance.analytics/index.js', '@mescius/wijmo.chart.hierarchical': 'npm:@mescius/wijmo.chart.hierarchical/index.js', '@mescius/wijmo.chart.interaction': 'npm:@mescius/wijmo.chart.interaction/index.js', '@mescius/wijmo.chart.radar': 'npm:@mescius/wijmo.chart.radar/index.js', '@mescius/wijmo.chart.render': 'npm:@mescius/wijmo.chart.render/index.js', '@mescius/wijmo.chart.webgl': 'npm:@mescius/wijmo.chart.webgl/index.js', '@mescius/wijmo.chart.map': 'npm:@mescius/wijmo.chart.map/index.js', '@mescius/wijmo.gauge': 'npm:@mescius/wijmo.gauge/index.js', '@mescius/wijmo.grid': 'npm:@mescius/wijmo.grid/index.js', '@mescius/wijmo.grid.detail': 'npm:@mescius/wijmo.grid.detail/index.js', '@mescius/wijmo.grid.filter': 'npm:@mescius/wijmo.grid.filter/index.js', '@mescius/wijmo.grid.search': 'npm:@mescius/wijmo.grid.search/index.js', '@mescius/wijmo.grid.style': 'npm:@mescius/wijmo.grid.style/index.js', '@mescius/wijmo.grid.grouppanel': 'npm:@mescius/wijmo.grid.grouppanel/index.js', '@mescius/wijmo.grid.multirow': 'npm:@mescius/wijmo.grid.multirow/index.js', '@mescius/wijmo.grid.transposed': 'npm:@mescius/wijmo.grid.transposed/index.js', '@mescius/wijmo.grid.transposedmultirow': 'npm:@mescius/wijmo.grid.transposedmultirow/index.js', '@mescius/wijmo.grid.pdf': 'npm:@mescius/wijmo.grid.pdf/index.js', '@mescius/wijmo.grid.sheet': 'npm:@mescius/wijmo.grid.sheet/index.js', '@mescius/wijmo.grid.xlsx': 'npm:@mescius/wijmo.grid.xlsx/index.js', '@mescius/wijmo.grid.selector': 'npm:@mescius/wijmo.grid.selector/index.js', '@mescius/wijmo.grid.cellmaker': 'npm:@mescius/wijmo.grid.cellmaker/index.js', '@mescius/wijmo.nav': 'npm:@mescius/wijmo.nav/index.js', '@mescius/wijmo.odata': 'npm:@mescius/wijmo.odata/index.js', '@mescius/wijmo.olap': 'npm:@mescius/wijmo.olap/index.js', '@mescius/wijmo.rest': 'npm:@mescius/wijmo.rest/index.js', '@mescius/wijmo.pdf': 'npm:@mescius/wijmo.pdf/index.js', '@mescius/wijmo.pdf.security': 'npm:@mescius/wijmo.pdf.security/index.js', '@mescius/wijmo.viewer': 'npm:@mescius/wijmo.viewer/index.js', '@mescius/wijmo.xlsx': 'npm:@mescius/wijmo.xlsx/index.js', '@mescius/wijmo.undo': 'npm:@mescius/wijmo.undo/index.js', '@mescius/wijmo.interop.grid': 'npm:@mescius/wijmo.interop.grid/index.js', '@mescius/wijmo.touch': 'npm:@mescius/wijmo.touch/index.js', '@mescius/wijmo.cloud': 'npm:@mescius/wijmo.cloud/index.js', '@mescius/wijmo.barcode': 'npm:@mescius/wijmo.barcode/index.js', '@mescius/wijmo.barcode.common': 'npm:@mescius/wijmo.barcode.common/index.js', '@mescius/wijmo.barcode.composite': 'npm:@mescius/wijmo.barcode.composite/index.js', '@mescius/wijmo.barcode.specialized': 'npm:@mescius/wijmo.barcode.specialized/index.js', '@mescius/spread-sheets': 'npm:@mescius/spread-sheets/index.js', '@mescius/spread-sheets-resources-ja': 'npm:@mescius/spread-sheets-resources-ja/index.js', '@mescius/spread-sheets/styles': 'npm:@mescius/spread-sheets/styles', 'css': 'npm:systemjs-plugin-css/css.js', 'plugin-babel': 'npm:systemjs-plugin-babel/plugin-babel.js', 'systemjs-babel-build': 'npm:systemjs-plugin-babel/systemjs-babel-browser.js', 'bootstrap.css': 'npm:bootstrap/dist/css/bootstrap.min.css', }, // packages tells the System loader how to load when no filename and/or no extension packages: { src: { defaultExtension: 'js' }, "node_modules": { defaultExtension: 'js' }, } });