ここでは、患者情報管理アプリを作成する際のポイントを紹介します。
診察予約のタブ
このタブでは、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;\">右: 左:</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;\">血色素量(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;\">糖: 蛋白:</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">
×
</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">
×
</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'
},
}
});