RoutePatient nested routes

This commit is contained in:
Jiang Yio 2023-05-08 18:48:29 -04:00
parent c15f7ed885
commit cdfa3b2f04
5 changed files with 115 additions and 159 deletions

View File

@ -15,6 +15,7 @@
import Login from './Login.vue'; import Login from './Login.vue';
import RouteSchedule from './RouteSchedule.vue'; import RouteSchedule from './RouteSchedule.vue';
import RouteLookup from './RouteLookup.vue'; import RouteLookup from './RouteLookup.vue';
import RoutePatient from './RoutePatient.vue';
import RoutePatientDetail from './RoutePatientDetail.vue'; import RoutePatientDetail from './RoutePatientDetail.vue';
import RoutePatientVisits from './RoutePatientVisits.vue'; import RoutePatientVisits from './RoutePatientVisits.vue';
import RoutePatientOrders from './RoutePatientOrders.vue'; import RoutePatientOrders from './RoutePatientOrders.vue';
@ -45,9 +46,11 @@
[ [
{ path: '/', component: RouteSchedule }, { path: '/', component: RouteSchedule },
{ path: '/lookup', component: RouteLookup }, { path: '/lookup', component: RouteLookup },
{ path: '/patient/:id', component: RoutePatientDetail }, { path: '/patient/:id', component: RoutePatient, children: [
{ path: '/patient/:id/visits', component: RoutePatientVisits }, { path: '', component: RoutePatientDetail },
{ path: '/patient/:id/orders', component: RoutePatientOrders }, { path: 'visits', component: RoutePatientVisits },
{ path: 'orders', component: RoutePatientOrders },
] },
{ path: '/planner', component: RoutePlanner }, { path: '/planner', component: RoutePlanner },
{ path: '/recall', component: RouteRecall }, { path: '/recall', component: RouteRecall },
].forEach(route => this.$root.$router.addRoute(route)); ].forEach(route => this.$root.$router.addRoute(route));

74
htdocs/RoutePatient.vue Normal file
View File

@ -0,0 +1,74 @@
<template>
<Subtitle value="Patient" />
<div v-if="(sensitive) && (!patient_info)" class="alert alert-danger text-center mb-3 shadow" role="alert">
<Subtitle value="Restricted Record" />
<h1>Warning: Restricted Record</h1>
<p>This record is protected by the Privacy Act of 1974 and the Health Insurance Portability and Accountability Act of 1996. If you elect to proceed, you will be required to prove you have a need to know. Accessing this patient is tracked, and your station Security Officer will contact you for your justification.</p>
<router-link class="btn btn-danger" :to="'/patient/' + patient_dfn + '?viewsensitive'">Proceed</router-link>
</div>
<template v-if="patient_info">
<div class="card mb-3 shadow">
<div class="card-header">{{patient_info.name}} <span :title="patient_info.pid">{{patient_info.pid.slice(-4)}}</span> #{{patient_dfn}}</div>
<div class="card-body row" style="font-family: monospace;">
<div class="col" v-if="patient_info.dob"><strong>DOB:</strong> {{strptime_vista(patient_info.dob).toLocaleDateString('sv-SE')}}</div>
<div class="col" v-if="patient_info.age"><strong>Age:</strong> {{patient_info.age}}</div>
<div class="col" v-if="patient_info.sex"><strong>Sex:</strong> {{patient_info.sex}}</div>
<div class="col" v-if="patient_info.sc_percentage"><strong>SC%:</strong> {{patient_info.sc_percentage}}</div>
<div class="col" v-if="patient_info.type"><strong>Type:</strong> {{patient_info.type}}</div>
<div class="col" v-if="patient_info.ward"><strong>Ward:</strong> {{patient_info.ward}}</div>
<div class="col" v-if="patient_info.room_bed"><strong>Room/bed:</strong> {{patient_info.room_bed}}</div>
</div>
</div>
<router-view :client="client" :sensitive="sensitive" :patient_dfn="patient_dfn" :patient_info="patient_info"></router-view>
</template>
</template>
<script>
import { strptime_vista } from './util.mjs';
import Subtitle from './Subtitle.vue';
export default {
components: {
Subtitle
},
props: {
client: Object
},
data() {
return {
sensitive: false,
patient_dfn: null,
patient_info: null
};
},
methods: {
strptime_vista,
async loadinfo(dfn, viewsensitive) {
this.patient_dfn = dfn;
this.sensitive = viewsensitive ? false : await this.client.ORWPT_SELCHK(dfn);
this.patient_info = this.sensitive ? null : await this.client.ORWPT16_ID_INFO(dfn);
}
},
async mounted() {
if(this.$route.params.id.startsWith('$')) {
var id = this.$route.params.id.substring(1);
if(id.length == 9) {
var patient = await this.client.ORWPT_FULLSSN(id);
this.$router.replace('/patient/' + patient[0].dfn);
} else if(id.length == 5) {
var name = this.$route.query.name.toUpperCase();
var patient = await this.client.ORWPT_LAST5(id);
for(var i = 0; i < patient.length; ++i) if(name == patient[i].name) {
this.$router.replace('/patient/' + patient[i].dfn);
break;
}
}
} else this.loadinfo(this.$route.params.id, this.$route.query.hasOwnProperty('viewsensitive'));
},
async beforeRouteUpdate(to, from, next) {
this.loadinfo(to.params.id, to.query.hasOwnProperty('viewsensitive'));
next();
}
};
</script>

View File

@ -1,39 +1,18 @@
<template> <template>
<Subtitle value="Detail" /> <Subtitle value="Detail" />
<div v-if="(sensitive) && (!info)" class="alert alert-danger text-center mb-3 shadow" role="alert"> <Subtitle :value="patient_info.name" />
<h1>Warning: Restricted Record</h1>
<p>This record is protected by the Privacy Act of 1974 and the Health Insurance Portability and Accountability Act of 1996. If you elect to proceed, you will be required to prove you have a need to know. Accessing this patient is tracked, and your station Security Officer will contact you for your justification.</p>
<router-link class="btn btn-danger" :to="'/patient/' + dfn + '?viewsensitive'">Proceed</router-link>
</div>
<div v-if="info">
<Subtitle :value="info.name" />
<div class="card mb-3 shadow">
<div class="card-header">{{info.name}} <span :title="info.pid">{{info.pid.slice(-4)}}</span> #{{dfn}}</div>
<div class="card-body row" style="font-family: monospace;">
<div class="col" v-if="info.dob"><strong>DOB:</strong> {{strptime_vista(info.dob).toLocaleDateString('sv-SE')}}</div>
<div class="col" v-if="info.age"><strong>Age:</strong> {{info.age}}</div>
<div class="col" v-if="info.sex"><strong>Sex:</strong> {{info.sex}}</div>
<div class="col" v-if="info.sc_percentage"><strong>SC%:</strong> {{info.sc_percentage}}</div>
<div class="col" v-if="info.type"><strong>Type:</strong> {{info.type}}</div>
<div class="col" v-if="info.ward"><strong>Ward:</strong> {{info.ward}}</div>
<div class="col" v-if="info.room_bed"><strong>Room/bed:</strong> {{info.room_bed}}</div>
</div>
</div>
<div class="card mb-3 shadow"> <div class="card mb-3 shadow">
<div class="card-header d-flex justify-content-between align-items-center"> <div class="card-header d-flex justify-content-between align-items-center">
<span>Data</span> <span>Data</span>
<DateRangePicker range="1M" direction="-1" v-model:date="report_date" v-model:date_end="report_date_begin" /> <DateRangePicker range="1M" direction="-1" v-model:date="report_date" v-model:date_end="report_date_begin" />
</div> </div>
<div class="card-body"> <div class="card-body">
<ViewVitalsLabs :client="client" :dfn="dfn" :date_begin="report_date_begin" :date_end="report_date" /> <ViewVitalsLabs :client="client" :dfn="patient_dfn" :date_begin="report_date_begin" :date_end="report_date" />
</div>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import { strptime_vista } from './util.mjs';
import Subtitle from './Subtitle.vue'; import Subtitle from './Subtitle.vue';
import DateRangePicker from './DateRangePicker.vue'; import DateRangePicker from './DateRangePicker.vue';
import ViewVitalsLabs from './ViewVitalsLabs.vue'; import ViewVitalsLabs from './ViewVitalsLabs.vue';
@ -45,47 +24,19 @@
Subtitle, DateRangePicker, ViewVitalsLabs Subtitle, DateRangePicker, ViewVitalsLabs
}, },
props: { props: {
client: Object client: Object,
sensitive: Boolean,
patient_dfn: String,
patient_info: Object
}, },
data() { data() {
return { return {
dfn: null,
sensitive: false,
info: null,
report_date: now, report_date: now,
report_date_begin: now, report_date_begin: now,
orders_filter: 2, orders_filter: 2,
orders_date: now, orders_date: now,
orders_date_begin: now orders_date_begin: now
}; };
},
methods: {
strptime_vista,
async loadinfo(dfn, viewsensitive) {
this.dfn = dfn;
this.sensitive = viewsensitive ? false : await this.client.ORWPT_SELCHK(dfn);
this.info = this.sensitive ? null : await this.client.ORWPT16_ID_INFO(dfn);
}
},
async mounted() {
if(this.$route.params.id.startsWith('$')) {
var id = this.$route.params.id.substring(1);
if(id.length == 9) {
var patient = await this.client.ORWPT_FULLSSN(id);
this.$router.replace('/patient/' + patient[0].dfn);
} else if(id.length == 5) {
var name = this.$route.query.name.toUpperCase();
var patient = await this.client.ORWPT_LAST5(id);
for(var i = 0; i < patient.length; ++i) if(name == patient[i].name) {
this.$router.replace('/patient/' + patient[i].dfn);
break;
}
}
} else this.loadinfo(this.$route.params.id, this.$route.query.hasOwnProperty('viewsensitive'));
},
async beforeRouteUpdate(to, from, next) {
this.loadinfo(to.params.id, to.query.hasOwnProperty('viewsensitive'));
next();
} }
}; };
</script> </script>

View File

@ -1,27 +1,9 @@
<template> <template>
<Subtitle value="Orders" /> <Subtitle value="Orders" />
<div v-if="(sensitive) && (!info)" class="alert alert-danger text-center mb-3 shadow" role="alert"> <Subtitle :value="patient_info.name" />
<h1>Warning: Restricted Record</h1>
<p>This record is protected by the Privacy Act of 1974 and the Health Insurance Portability and Accountability Act of 1996. If you elect to proceed, you will be required to prove you have a need to know. Accessing this patient is tracked, and your station Security Officer will contact you for your justification.</p>
<router-link class="btn btn-danger" :to="'/patient/' + dfn + '/orders?viewsensitive'">Proceed</router-link>
</div>
<div v-if="info">
<Subtitle :value="info.name" />
<div class="card mb-3 shadow">
<div class="card-header">{{info.name}} <span :title="info.pid">{{info.pid.slice(-4)}}</span> #{{dfn}}</div>
<div class="card-body row" style="font-family: monospace;">
<div class="col" v-if="info.dob"><strong>DOB:</strong> {{strptime_vista(info.dob).toLocaleDateString('sv-SE')}}</div>
<div class="col" v-if="info.age"><strong>Age:</strong> {{info.age}}</div>
<div class="col" v-if="info.sex"><strong>Sex:</strong> {{info.sex}}</div>
<div class="col" v-if="info.sc_percentage"><strong>SC%:</strong> {{info.sc_percentage}}</div>
<div class="col" v-if="info.type"><strong>Type:</strong> {{info.type}}</div>
<div class="col" v-if="info.ward"><strong>Ward:</strong> {{info.ward}}</div>
<div class="col" v-if="info.room_bed"><strong>Room/bed:</strong> {{info.room_bed}}</div>
</div>
</div>
<div class="card mb-3 shadow"> <div class="card mb-3 shadow">
<div class="card-header">Order entry</div> <div class="card-header">Order entry</div>
<div class="card-body"><ViewOrderMenu :client="client" :dfn="dfn" /></div> <div class="card-body"><ViewOrderMenu :client="client" :dfn="patient_dfn" /></div>
</div> </div>
<div class="card mb-3 shadow"> <div class="card mb-3 shadow">
<div class="card-header d-flex justify-content-between align-items-center"> <div class="card-header d-flex justify-content-between align-items-center">
@ -29,14 +11,11 @@
<OrderFilterPicker :client="client" v-model="orders_filter" /> <OrderFilterPicker :client="client" v-model="orders_filter" />
<DateRangePicker range="6M" direction="-1" v-model:date="orders_date" v-model:date_end="orders_date_begin" /> <DateRangePicker range="6M" direction="-1" v-model:date="orders_date" v-model:date_end="orders_date_begin" />
</div> </div>
<div class="card-body"><ViewOrders :client="client" :dfn="dfn" :filter="orders_filter" :date_begin="orders_date_begin" :date_end="orders_date" /></div> <div class="card-body"><ViewOrders :client="client" :dfn="patient_dfn" :filter="orders_filter" :date_begin="orders_date_begin" :date_end="orders_date" /></div>
</div>
</div> </div>
</template> </template>
<script> <script>
import { strptime_vista } from './util.mjs';
import Subtitle from './Subtitle.vue'; import Subtitle from './Subtitle.vue';
import DateRangePicker from './DateRangePicker.vue'; import DateRangePicker from './DateRangePicker.vue';
import OrderFilterPicker from './OrderFilterPicker.vue'; import OrderFilterPicker from './OrderFilterPicker.vue';
@ -50,32 +29,17 @@
Subtitle, DateRangePicker, OrderFilterPicker, ViewOrderMenu, ViewOrders Subtitle, DateRangePicker, OrderFilterPicker, ViewOrderMenu, ViewOrders
}, },
props: { props: {
client: Object client: Object,
sensitive: Boolean,
patient_dfn: String,
patient_info: Object
}, },
data() { data() {
return { return {
dfn: null,
sensitive: false,
info: null,
orders_filter: 2, orders_filter: 2,
orders_date: now, orders_date: now,
orders_date_begin: now orders_date_begin: now
}; };
},
methods: {
strptime_vista,
async loadinfo(dfn, viewsensitive) {
this.dfn = dfn;
this.sensitive = viewsensitive ? false : await this.client.ORWPT_SELCHK(dfn);
this.info = this.sensitive ? null : await this.client.ORWPT16_ID_INFO(dfn);
}
},
async mounted() {
this.loadinfo(this.$route.params.id, this.$route.query.hasOwnProperty('viewsensitive'));
},
async beforeRouteUpdate(to, from, next) {
this.loadinfo(to.params.id, to.query.hasOwnProperty('viewsensitive'));
next();
} }
}; };
</script> </script>

View File

@ -1,37 +1,16 @@
<template> <template>
<Subtitle value="Visits" /> <Subtitle value="Visits" />
<div v-if="(sensitive) && (!info)" class="alert alert-danger text-center mb-3 shadow" role="alert"> <Subtitle :value="patient_info.name" />
<h1>Warning: Restricted Record</h1>
<p>This record is protected by the Privacy Act of 1974 and the Health Insurance Portability and Accountability Act of 1996. If you elect to proceed, you will be required to prove you have a need to know. Accessing this patient is tracked, and your station Security Officer will contact you for your justification.</p>
<router-link class="btn btn-danger" :to="'/patient/' + dfn + '/orders?viewsensitive'">Proceed</router-link>
</div>
<div v-if="info">
<Subtitle :value="info.name" />
<div class="card mb-3 shadow">
<div class="card-header">{{info.name}} <span :title="info.pid">{{info.pid.slice(-4)}}</span> #{{dfn}}</div>
<div class="card-body row" style="font-family: monospace;">
<div class="col" v-if="info.dob"><strong>DOB:</strong> {{strptime_vista(info.dob).toLocaleDateString('sv-SE')}}</div>
<div class="col" v-if="info.age"><strong>Age:</strong> {{info.age}}</div>
<div class="col" v-if="info.sex"><strong>Sex:</strong> {{info.sex}}</div>
<div class="col" v-if="info.sc_percentage"><strong>SC%:</strong> {{info.sc_percentage}}</div>
<div class="col" v-if="info.type"><strong>Type:</strong> {{info.type}}</div>
<div class="col" v-if="info.ward"><strong>Ward:</strong> {{info.ward}}</div>
<div class="col" v-if="info.room_bed"><strong>Room/bed:</strong> {{info.room_bed}}</div>
</div>
</div>
<div class="card mb-3 shadow"> <div class="card mb-3 shadow">
<div class="card-header d-flex justify-content-between align-items-center"> <div class="card-header d-flex justify-content-between align-items-center">
<span>Visits</span> <span>Visits</span>
<DateRangePicker range="6M" direction="-1" v-model:date="visits_date" v-model:date_end="visits_date_begin" /> <DateRangePicker range="6M" direction="-1" v-model:date="visits_date" v-model:date_end="visits_date_begin" />
</div> </div>
<div class="card-body"><ViewVisits :client="client" :dfn="dfn" :date_begin="visits_date_begin" :date_end="visits_date" /></div> <div class="card-body"><ViewVisits :client="client" :dfn="patient_dfn" :date_begin="visits_date_begin" :date_end="visits_date" /></div>
</div>
</div> </div>
</template> </template>
<script> <script>
import { strptime_vista } from './util.mjs';
import Subtitle from './Subtitle.vue'; import Subtitle from './Subtitle.vue';
import DateRangePicker from './DateRangePicker.vue'; import DateRangePicker from './DateRangePicker.vue';
import OrderFilterPicker from './OrderFilterPicker.vue'; import OrderFilterPicker from './OrderFilterPicker.vue';
@ -44,32 +23,17 @@
Subtitle, DateRangePicker, OrderFilterPicker, ViewVisits Subtitle, DateRangePicker, OrderFilterPicker, ViewVisits
}, },
props: { props: {
client: Object client: Object,
sensitive: Boolean,
patient_dfn: String,
patient_info: Object
}, },
data() { data() {
return { return {
dfn: null,
sensitive: false,
info: null,
orders_filter: 2, orders_filter: 2,
visits_date: now, visits_date: now,
visits_date_begin: now visits_date_begin: now
}; };
},
methods: {
strptime_vista,
async loadinfo(dfn, viewsensitive) {
this.dfn = dfn;
this.sensitive = viewsensitive ? false : await this.client.ORWPT_SELCHK(dfn);
this.info = this.sensitive ? null : await this.client.ORWPT16_ID_INFO(dfn);
}
},
async mounted() {
this.loadinfo(this.$route.params.id, this.$route.query.hasOwnProperty('viewsensitive'));
},
async beforeRouteUpdate(to, from, next) {
this.loadinfo(to.params.id, to.query.hasOwnProperty('viewsensitive'));
next();
} }
}; };
</script> </script>