Compare commits

...

4 Commits

Author SHA1 Message Date
cc5ec1f69f Active link style 2023-05-06 12:35:44 -04:00
b57634f730 Reactive title 2023-05-06 12:26:09 -04:00
535302ce9d Link from planner to patient 2023-05-06 08:30:37 -04:00
6970c62276 Throbber class 2023-05-06 08:22:43 -04:00
11 changed files with 76 additions and 27 deletions

View File

@ -40,6 +40,12 @@
</nav>
</template>
<style scoped>
a.router-link-exact-active {
color: #bbb;
}
</style>
<script>
import vistax from './vistax.mjs';

View File

@ -1,10 +1,12 @@
<template>
<Subtitle value="Detail" />
<div v-if="(sensitive) && (!info)" class="alert alert-danger text-center mb-3 shadow" role="alert">
<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;">
@ -32,6 +34,7 @@
<script>
import { strptime_vista } from './util.mjs';
import Subtitle from './Subtitle.vue';
import DateRangePicker from './DateRangePicker.vue';
import ViewVitalsLabs from './ViewVitalsLabs.vue';
@ -39,7 +42,7 @@
export default {
components: {
DateRangePicker, ViewVitalsLabs
Subtitle, DateRangePicker, ViewVitalsLabs
},
props: {
client: Object
@ -56,11 +59,6 @@
orders_date_begin: now
};
},
watch: {
info(value) {
if((value) && (value.name)) document.title = value.name;
}
},
methods: {
strptime_vista,
async loadinfo(dfn, viewsensitive) {

View File

@ -1,4 +1,5 @@
<template>
<Subtitle value="Lookup" />
<div>
<div class="card mb-3 shadow">
<div class="card-header">Patients</div>
@ -10,11 +11,12 @@
</template>
<script>
import Subtitle from './Subtitle.vue';
import ViewPatientLookup from './ViewPatientLookup.vue';
export default {
components: {
ViewPatientLookup
Subtitle, ViewPatientLookup
},
props: {
client: Object

View File

@ -1,10 +1,12 @@
<template>
<Subtitle value="Orders" />
<div v-if="(sensitive) && (!info)" class="alert alert-danger text-center mb-3 shadow" role="alert">
<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;">
@ -35,6 +37,7 @@
<script>
import { strptime_vista } from './util.mjs';
import Subtitle from './Subtitle.vue';
import DateRangePicker from './DateRangePicker.vue';
import OrderFilterPicker from './OrderFilterPicker.vue';
import ViewOrderMenu from './ViewOrderMenu.vue';
@ -44,7 +47,7 @@
export default {
components: {
DateRangePicker, OrderFilterPicker, ViewOrderMenu, ViewOrders
Subtitle, DateRangePicker, OrderFilterPicker, ViewOrderMenu, ViewOrders
},
props: {
client: Object
@ -59,11 +62,6 @@
orders_date_begin: now
};
},
watch: {
info(value) {
if((value) && (value.name)) document.title = value.name;
}
},
methods: {
strptime_vista,
async loadinfo(dfn, viewsensitive) {

View File

@ -1,10 +1,12 @@
<template>
<Subtitle value="Visits" />
<div v-if="(sensitive) && (!info)" class="alert alert-danger text-center mb-3 shadow" role="alert">
<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;">
@ -30,6 +32,7 @@
<script>
import { strptime_vista } from './util.mjs';
import Subtitle from './Subtitle.vue';
import DateRangePicker from './DateRangePicker.vue';
import OrderFilterPicker from './OrderFilterPicker.vue';
import ViewVisits from './ViewVisits.vue';
@ -38,7 +41,7 @@
export default {
components: {
DateRangePicker, OrderFilterPicker, ViewVisits
Subtitle, DateRangePicker, OrderFilterPicker, ViewVisits
},
props: {
client: Object
@ -53,11 +56,6 @@
visits_date_begin: now
};
},
watch: {
info(value) {
if((value) && (value.name)) document.title = value.name;
}
},
methods: {
strptime_vista,
async loadinfo(dfn, viewsensitive) {

View File

@ -1,4 +1,5 @@
<template>
<Subtitle value="Planner" />
<div class="card mb-3 shadow">
<div class="card-header d-flex justify-content-between align-items-center">
<span>Planner</span>
@ -10,12 +11,13 @@
</template>
<script>
import Subtitle from './Subtitle.vue';
import DateRangePicker from './DateRangePicker.vue';
import ViewPlanner from './ViewPlanner.vue';
export default {
components: {
DateRangePicker, ViewPlanner
Subtitle, DateRangePicker, ViewPlanner
},
props: {
client: Object

View File

@ -1,4 +1,5 @@
<template>
<Subtitle value="Recall" />
<div>
<div class="card mb-3 shadow">
<div class="card-header">Clinics</div>
@ -47,6 +48,7 @@
<script>
import { groupByArray, strtr_unscramble, strHashHSL, strftime_vista, debounce } from './util.mjs';
import Subtitle from './Subtitle.vue';
import ViewResourceLookup from './ViewResourceLookup.vue';
function dateonly(date) {
@ -55,7 +57,7 @@
export default {
components: {
ViewResourceLookup
Subtitle, ViewResourceLookup
},
props: {
client: Object

View File

@ -1,4 +1,5 @@
<template>
<Subtitle value="Schedule" />
<div>
<div class="card mb-3 shadow">
<div class="card-header">Clinics</div>
@ -19,6 +20,7 @@
</template>
<script>
import Subtitle from './Subtitle.vue';
import ViewResourceLookup from './ViewResourceLookup.vue';
import DateRangePicker from './DateRangePicker.vue';
import ViewSchedule from './ViewSchedule.vue';
@ -29,7 +31,7 @@
export default {
components: {
ViewResourceLookup, DateRangePicker, ViewSchedule
Subtitle, ViewResourceLookup, DateRangePicker, ViewSchedule
},
props: {
client: Object

41
htdocs/Subtitle.vue Normal file
View File

@ -0,0 +1,41 @@
<script>
import { debounce } from './util.mjs';
const base = 'nuVistA';
const state = [{ value: base }];
const settitle = debounce(s => document.title = s || base, 0);
export default {
props: ['value'],
data() {
return { ptr: null };
},
watch: {
value: {
handler(value) {
this.update(value);
}, immediate: true
}
},
methods: {
update(value) {
if(value) {
if(this.ptr) this.ptr.value = value;
else {
this.ptr = { value };
state.unshift(this.ptr);
}
} else if(this.ptr) {
var idx = state.indexOf(this.ptr);
if(idx >= 0) state.splice(idx, 1);
this.ptr = null;
}
settitle(state.map(x => x.value).join(' - '));
}
},
unmounted() {
this.update();
},
render() {}
};
</script>

View File

@ -1,9 +1,9 @@
<template>
<div :class="{ connected, idle }" />
<div class="throbber" :class="{ connected, idle }" />
</template>
<style scoped>
div {
div.throbber {
position: fixed;
top: 59px;
right: 0;
@ -12,7 +12,7 @@
z-index: 1030;
background-color: #dc3545;
}
div.connected {
div.throbber.connected {
background-color: #0d6efd;
background-image: repeating-linear-gradient(
-45deg,
@ -25,7 +25,7 @@
animation: barberpole 60s linear infinite;
animation-direction: reverse;
}
div.idle {
div.throbber.idle {
visibility: hidden;
opacity: 0;
transition: visibility 0s 0.5s, opacity 0.5s linear;

View File

@ -10,7 +10,7 @@
<div class="datebox" :style="{ backgroundColor: resultset.max > 0 ? 'rgba(220, 53, 69, ' + week.values[day].length/resultset.max + ')' : null }"><span class="occupancy hidden">#{{week.values[day].length}}</span> {{day > 0 ? week.values[day][0]._START_OBJ.getDate() : week.key.toLocaleDateString('sv-SE')}} <span class="occupancy">#{{week.values[day].length}}</span></div>
<template v-for="appointment in week.values[day]">
<div v-if="appointment._BREAK" class="vacancy" :title="appointment._START_OBJ.toLocaleTimeString('en-GB').substring(0, 5) + '' + appointment._END_OBJ.toLocaleTimeString('en-GB').substring(0, 5)" />
<div v-else :title="appointment._START_OBJ.toLocaleTimeString('en-GB').substring(0, 5) + '' + appointment._END_OBJ.toLocaleTimeString('en-GB').substring(0, 5) + '\n' + appointment.PATIENTNAME + ' ' + appointment.HRN.slice(-4) + '\n' + appointment.NOTE"><span v-if="appointment._CONCURRENCY > 0" class="concurrency hidden">*<template v-if="appointment._CONCURRENCY > 1">{{appointment._CONCURRENCY}}</template></span>{{appointment._START_OBJ.toLocaleTimeString('en-GB').substring(0, 5)}} {{appointment.PATIENTNAME.substring(0, 1)}}{{appointment.HRN.slice(-4)}}<span v-if="appointment._CONCURRENCY > 0" class="concurrency">*<template v-if="appointment._CONCURRENCY > 1">{{appointment._CONCURRENCY}}</template></span></div>
<div v-else :title="appointment._START_OBJ.toLocaleTimeString('en-GB').substring(0, 5) + '' + appointment._END_OBJ.toLocaleTimeString('en-GB').substring(0, 5) + '\n' + appointment.PATIENTNAME + ' ' + appointment.HRN.slice(-4) + '\n' + appointment.NOTE"><span v-if="appointment._CONCURRENCY > 0" class="concurrency hidden">*<template v-if="appointment._CONCURRENCY > 1">{{appointment._CONCURRENCY}}</template></span>{{appointment._START_OBJ.toLocaleTimeString('en-GB').substring(0, 5)}} <router-link :to="'/patient/' + appointment.PATIENTID">{{appointment.PATIENTNAME.substring(0, 1)}}{{appointment.HRN.slice(-4)}}</router-link><span v-if="appointment._CONCURRENCY > 0" class="concurrency">*<template v-if="appointment._CONCURRENCY > 1">{{appointment._CONCURRENCY}}</template></span></div>
</template>
</template>
<div v-else class="datebox">{{day > 0 ? (new Date(week.key.getTime() + 1000*60*60*24*day)).getDate() : week.key.toLocaleDateString('sv-SE')}}</div>