nuVistA/htdocs/RoutePatientDocuments.vue

200 lines
5.3 KiB
Vue
Raw Normal View History

2023-05-10 21:55:15 -04:00
<template>
<Subtitle value="Documents" />
<Subtitle :value="patient_info.name" />
<div class="row">
<div class="selector col-12 col-xl-4">
<div class="card mb-3 shadow">
<div class="card-header"><template v-if="resultset.length > 0">{{resultset.length}}<template v-if="has_more">+</template></template><template v-else>No</template> record{{resultset.length == 1 ? '' : 's'}}</div>
<ul class="scroller list-group list-group-flush" ref="scroller">
<router-link v-for="item in resultset" :to="'/patient/' + patient_dfn + '/document/' + item.IEN + (sensitive ? '?viewsensitive' : '')" replace custom v-slot="{ navigate, href }">
<li :key="item" class="record" :class="{ 'active': selection == item.IEN }" :title="datetimestring(strptime_vista(item.time)) + '\n' + item.title + '\n' + item.location + '\n' + item.author.byline" @click="navigate">
<div class="row">
<div class="cell col-4"><router-link :to="href" replace>{{datestring(strptime_vista(item.time))}}</router-link></div>
<div class="cell col-8">{{item.title}}</div>
<div class="cell secondary col-7 col-lg-4 col-xl-7">{{item.location}}</div>
<div class="cell secondary col-5 col-lg-8 col-xl-5">{{item.author.byline}}</div>
</div>
</li>
</router-link>
<li ref="bottom" />
</ul>
</div>
</div>
<div v-if="selection_text" class="col-12 col-xl-8">
<div class="card mb-3 shadow">
<div class="card-header">{{doctitle(selection_text) || 'Document'}}</div>
<div class="detail card-body">{{selection_text}}</div>
</div>
</div>
</div>
</template>
<style scoped>
div.selector {
position: sticky;
top: 1.15rem;
z-index: 1;
}
ul.scroller {
max-height: 25vh;
overflow-y: auto;
}
li.record {
cursor: default;
border-top: 1px solid #dee2e6;
padding: 0.25rem 0.75rem;
}
li.record:nth-child(even) {
background-color: rgba(0, 0, 0, 0.05);
}
li.record a {
color: inherit;
}
li.record.active {
color: #fff;
background-color: #0d6efd;
}
div.cell {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
div.detail {
font-family: monospace;
white-space: pre-wrap;
}
@media (min-width: 1200px) {
div.selector {
position: static;
}
ul.scroller {
max-height: 75vh;
}
div.cell.secondary {
font-size: 0.8em;
}
div.detail {
max-height: 75vh;
overflow-y: auto;
}
}
</style>
<script>
import { debounce, strptime_vista } from './util.mjs';
import Subtitle from './Subtitle.vue';
const SZ_WINDOW = 100;
export default {
components: {
Subtitle
},
props: {
client: Object,
sensitive: Boolean,
patient_dfn: String,
patient_info: Object
},
data() {
return {
dfn: null,
has_more: '',
is_loading: false,
resultset: [],
selection: null,
selection_text: null,
observer_bottom: null
};
},
watch: {
'$route.params.tiu_da': {
async handler(value) {
this.selection = value;
}, immediate: true
}
},
methods: {
strptime_vista,
datestring(date) {
return date.toLocaleDateString('sv-SE');
},
datetimestring(date) {
return date.toLocaleDateString('sv-SE') + ' ' + date.toLocaleTimeString('en-GB');
},
doctitle(doc) {
if(doc) {
var brk = doc.indexOf('\r\n');
if(brk >= 0) {
doc = doc.substring(0, brk);
brk = doc.indexOf(': ');
if(brk >= 0) return doc.substring(brk + 2).replace(/^\s+|\s+$/g, '');
else return doc.replace(/^\s+|\s+$/g, '');
}
}
},
async load_more() {
try {
this.is_loading = true;
if((this.client) && (this.patient_dfn)) {
if(this.dfn != this.patient_dfn) {
this.dfn = this.patient_dfn;
this.has_more = '';
this.resultset = [];
}
var res = await client.TIU_DOCUMENTS_BY_CONTEXT(3, 1, this.patient_dfn, -1, -1, 0, SZ_WINDOW, 'D', 1, 0, 1, this.has_more);
if((res) && (res.length > 0)) {
res = res.slice();
var last = res[res.length - 1];
if((last.title == 'SHOW MORE') && (!last.author) && (!last.visit)) {
this.has_more = last.IEN;
res.splice(res.length - 1, 1);
}
if(this.resultset.length > 0) Array.prototype.push.apply(this.resultset, res);
else this.resultset = res;
}
} else {
this.dfn = null;
this.has_more = '';
this.resultset = [];
}
} catch(ex) {
console.warn(ex);
} finally {
this.is_loading = false;
}
},
handle_bottom([entry]) {
if((entry.isIntersecting) && (this.has_more) && (!this.is_loading)) this.load_more();
}
},
created() {
this.$watch(
() => (this.client, this.patient_dfn, {}),
debounce(this.load_more, 500),
{ immediate: true }
);
this.$watch(
() => (this.client, this.selection, {}),
debounce(async function() {
try {
this.selection_text = (this.client) && (this.selection) ? await this.client.TIU_GET_RECORD_TEXT(this.selection) : null;
} catch(ex) {
this.selection_text = null;
console.warn(ex);
}
}, 500),
{ immediate: true }
);
},
mounted() {
this.observer_bottom = new IntersectionObserver(this.handle_bottom, { root: this.$refs.scroller, rootMargin: '25%' });
this.observer_bottom.observe(this.$refs.bottom);
},
destroyed() {
if(this.observer_bottom) this.observer_bottom.disconnect();
}
};
</script>