Compare commits
No commits in common. "eebda06c86fe66a598b6c317c9efdda24d9e30df" and "770a9cfb2e1c1fbb9677ad26e269d2de76fa9af7" have entirely different histories.
eebda06c86
...
770a9cfb2e
@ -7,7 +7,7 @@
|
|||||||
<div class="accordion-body" v-else>
|
<div class="accordion-body" v-else>
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<p class="card-text row"><code class="col" v-if="banner"><pre>{{banner.join('\n')}}</pre></code><code class="col" v-if="authinfo"><pre v-if="(authinfo.greeting) && (authinfo.greeting.length > 0)">{{authinfo.greeting.join('\n').replace(/^\n+|\s+$/gm, '')}}</pre><pre v-if="user">{{user.join('\n')}}</pre></code></p>
|
<p class="card-text row"><code class="col" v-if="banner"><pre>{{banner.join('\n')}}</pre></code><code class="col" v-if="user"><pre>{{user.join('\n')}}</pre></code></p>
|
||||||
</div>
|
</div>
|
||||||
<button class="btn btn-danger" style="width: 100%;" type="button" v-if="user" v-on:click="logout">Logout</button>
|
<button class="btn btn-danger" style="width: 100%;" type="button" v-if="user" v-on:click="logout">Logout</button>
|
||||||
<div class="input-group flex-nowrap" v-if="!user">
|
<div class="input-group flex-nowrap" v-if="!user">
|
||||||
@ -81,7 +81,6 @@
|
|||||||
x_server: this.server,
|
x_server: this.server,
|
||||||
x_user: this.user,
|
x_user: this.user,
|
||||||
banner: null,
|
banner: null,
|
||||||
authinfo: null,
|
|
||||||
accesscode: null,
|
accesscode: null,
|
||||||
verifycode: null
|
verifycode: null
|
||||||
};
|
};
|
||||||
@ -122,7 +121,7 @@
|
|||||||
this.logout();
|
this.logout();
|
||||||
if(this.x_client = await (this.host ? vistax.Client.fromCookie(this.secret, this.host) : vistax.Client.fromCookie(this.secret))) {
|
if(this.x_client = await (this.host ? vistax.Client.fromCookie(this.secret, this.host) : vistax.Client.fromCookie(this.secret))) {
|
||||||
this.banner = await this.x_client.XUS_INTRO_MSG();
|
this.banner = await this.x_client.XUS_INTRO_MSG();
|
||||||
if((this.authinfo = await this.x_client.authinfo()).success) try {
|
if((await this.x_client.userinfo()).result) try {
|
||||||
var user = await this.x_client.XUS_GET_USER_INFO();
|
var user = await this.x_client.XUS_GET_USER_INFO();
|
||||||
this.x_user = user[0] ? user : null
|
this.x_user = user[0] ? user : null
|
||||||
} catch(ex) {
|
} catch(ex) {
|
||||||
@ -137,32 +136,20 @@
|
|||||||
} else {
|
} else {
|
||||||
this.fail = true;
|
this.fail = true;
|
||||||
this.host = undefined;
|
this.host = undefined;
|
||||||
this.authinfo = null;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async login(evt) {
|
async login(evt) {
|
||||||
if(this.x_client) {
|
if(this.x_client) {
|
||||||
try {
|
var res = await ((this.accesscode && this.verifycode) ? this.x_client.authenticate(this.accesscode + ';' + this.verifycode) : this.x_client.authenticate());
|
||||||
this.authinfo = await ((this.accesscode && this.verifycode) ? this.x_client.authenticate(this.accesscode + ';' + this.verifycode) : this.x_client.authenticate());
|
if(!!res.result[0]) {
|
||||||
if(this.authinfo.duz) {
|
var user = await this.x_client.XUS_GET_USER_INFO();
|
||||||
var user = await this.x_client.XUS_GET_USER_INFO();
|
this.x_user = user[0] ? user : null
|
||||||
this.x_user = user[0] ? user : null
|
} else this.x_user = null;
|
||||||
} else {
|
|
||||||
this.x_user = null;
|
|
||||||
if(this.authinfo.message) window.alert(this.authinfo.message);
|
|
||||||
else window.alert('Authentication failed.');
|
|
||||||
}
|
|
||||||
} catch(ex) {
|
|
||||||
this.authinfo = this.x_user = null;
|
|
||||||
console.warn(ex);
|
|
||||||
if(ex.name) window.alert(ex.name);
|
|
||||||
else window.alert('Authentication failed.');
|
|
||||||
}
|
|
||||||
this.$emit('update:user', this.x_user);
|
this.$emit('update:user', this.x_user);
|
||||||
this.show = !this.x_user;
|
this.show = !this.x_user;
|
||||||
this.$emit('update:server', this.x_server = (await this.x_client.serverinfo()).result);
|
this.$emit('update:server', this.x_server = (await this.x_client.serverinfo()).result);
|
||||||
console.log('Authenticate', this.authinfo);
|
console.log('Authenticate', res);
|
||||||
} else this.authinfo = null;
|
}
|
||||||
},
|
},
|
||||||
async logout(evt) {
|
async logout(evt) {
|
||||||
if(this.x_client) {
|
if(this.x_client) {
|
||||||
|
@ -1,84 +0,0 @@
|
|||||||
<template>
|
|
||||||
<TransitionGroup>
|
|
||||||
<div v-if="x_show" class="modal show" style="display: block;" tabindex="-1" @keydown.enter="submit" @keydown.esc="cancel">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h5 class="modal-title">{{label || 'Sign'}}</h5>
|
|
||||||
<button type="button" class="btn-close" @click="cancel"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<div class="input-group">
|
|
||||||
<span class="input-group-text">Code</span>
|
|
||||||
<input ref="input" type="password" class="form-control" :class="{ 'is-invalid': valid === false }" v-model="x_modelValue" @input="() => valid = null" />
|
|
||||||
<div v-if="valid === false" class="invalid-feedback">Invalid code.</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-primary" :disabled="!x_modelValue" @click="submit">Submit</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div v-if="x_show" class="modal-backdrop show"></div>
|
|
||||||
</TransitionGroup>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.v-enter-active, .v-leave-active {
|
|
||||||
transition: opacity 0.25s ease;
|
|
||||||
}
|
|
||||||
.v-enter-from, .v-leave-to {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
props: {
|
|
||||||
client: Object,
|
|
||||||
show: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
label: String,
|
|
||||||
modelValue: null
|
|
||||||
},
|
|
||||||
emits: {
|
|
||||||
'cancel': null,
|
|
||||||
'submit': String,
|
|
||||||
'update:show': String,
|
|
||||||
'update:modelValue': null
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
valid: null,
|
|
||||||
x_show: this.show,
|
|
||||||
x_modelValue: this.modelValue
|
|
||||||
};
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
show(value) { this.x_show = value; },
|
|
||||||
async x_show(value) {
|
|
||||||
this.x_modelValue = '';
|
|
||||||
this.$emit('update:show', value);
|
|
||||||
await this.$nextTick();
|
|
||||||
if((value) && (this.$refs.input)) this.$refs.input.focus();
|
|
||||||
},
|
|
||||||
modelValue(value) { this.x_modelValue = value; },
|
|
||||||
x_modelValue(value) { this.$emit('update:modelValue', value); }
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
cancel() { this.x_show = false; },
|
|
||||||
async submit() {
|
|
||||||
var value = this.x_modelValue;
|
|
||||||
if((this.client) && (value)) {
|
|
||||||
if(this.valid = (await this.client.ORWU_VALIDSIG(' ' + value + ' ')) == '1') {
|
|
||||||
this.x_show = false;
|
|
||||||
this.$emit('submit', value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
|
@ -2,23 +2,15 @@
|
|||||||
<Subtitle value="Documents" />
|
<Subtitle value="Documents" />
|
||||||
<Subtitle :value="patient_info.name" />
|
<Subtitle :value="patient_info.name" />
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="selector col-12" :class="{ 'col-xl-4': selection }">
|
<div class="selector col-12" :class="{ 'col-xl-4': selection_text }">
|
||||||
<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"><template v-if="resultset.length > 0">{{resultset.length}}<template v-if="has_more">+</template></template><template v-else-if="is_loading">Loading</template><template v-else>No</template> record{{resultset.length == 1 ? '' : 's'}}</div>
|
||||||
<span><template v-if="resultset.length > 0">{{resultset.length}}<template v-if="has_more">+</template></template><template v-else-if="is_loading">Loading</template><template v-else>No</template> record{{resultset.length == 1 ? '' : 's'}}</span>
|
<ul class="scroller list-group list-group-flush" :class="{ 'list-skinny': selection_text }" ref="scroller">
|
||||||
<router-link :to="'/patient/' + patient_dfn + '/document/new'">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 16 16" style="width: 1.25em; height: 1.25em; vertical-align: text-bottom;">
|
|
||||||
<path d="M14 1a1 1 0 0 1 1 1v12a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1h12zM2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2z"/>
|
|
||||||
<path d="M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4z"/>
|
|
||||||
</svg>
|
|
||||||
</router-link>
|
|
||||||
</div>
|
|
||||||
<ul class="scroller list-group list-group-flush" :class="{ 'list-skinny': selection }" ref="scroller">
|
|
||||||
<router-link v-for="item in resultset" :to="'/patient/' + patient_dfn + '/document/' + item.IEN" replace custom v-slot="{ navigate, href }">
|
<router-link v-for="item in resultset" :to="'/patient/' + patient_dfn + '/document/' + item.IEN" replace custom v-slot="{ navigate, href }">
|
||||||
<li :key="item" class="record list-group-item" :class="{ 'active': selection == item.IEN }" :title="datetimestring(strptime_vista(item.time)) + '\n' + item.title + '\n' + item.location + '\n' + item.author.byline" @click="navigate">
|
<li :key="item" class="record list-group-item" :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="row">
|
||||||
<div class="cell col-4"><router-link :to="href" replace>{{datestring(strptime_vista(item.time))}}</router-link></div>
|
<div class="cell col-4"><router-link :to="href" replace>{{datestring(strptime_vista(item.time))}}</router-link></div>
|
||||||
<div class="cell col-8"><template v-if="item.status == 'unsigned'">✱</template>{{item.title}}</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-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 class="cell secondary col-5 col-lg-8 col-xl-5">{{item.author.byline}}</div>
|
||||||
</div>
|
</div>
|
||||||
@ -28,14 +20,16 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="selection == 'new'" class="col-12 col-xl-8">
|
<div v-if="selection_text" class="col-12 col-xl-8">
|
||||||
<ViewDocNew :client="client" :dfn="patient_dfn" :datetime="datetimestring(new Date())" @cancel="() => $router.replace({ path: '/patient/' + patient_dfn + '/document' })" @submit="doc_create" />
|
<div class="card mb-3 shadow">
|
||||||
</div>
|
<div class="card-header d-flex justify-content-between align-items-center">
|
||||||
<div v-else-if="selection" class="detail col-12 col-xl-8" ref="detail">
|
<span>{{doctitle(selection_text) || 'Document'}}</span>
|
||||||
<ViewDocView :client="client" :dfn="patient_dfn" :ien="selection" @sign="doc_sign_prompt" @delete="doc_delete" @cancel="() => $router.replace({ path: '/patient/' + patient_dfn + '/document' })" />
|
<router-link class="close" :to="'/patient/' + patient_dfn + '/document'" replace>❌</router-link>
|
||||||
|
</div>
|
||||||
|
<div class="detail card-body" ref="detail">{{selection_text}}</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ModalPromptSignatureCode :client="client" v-model:show="show_signature" @submit="doc_sign" label="Sign Document" />
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
@ -79,7 +73,7 @@
|
|||||||
cursor: default;
|
cursor: default;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
div.detail /deep/ .card-body {
|
div.detail {
|
||||||
scroll-margin-top: calc(3.6875rem + 2.5625rem + 25vh);
|
scroll-margin-top: calc(3.6875rem + 2.5625rem + 25vh);
|
||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
@ -94,7 +88,7 @@
|
|||||||
div.cell.secondary {
|
div.cell.secondary {
|
||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
}
|
}
|
||||||
div.detail /deep/ .card-body {
|
div.detail {
|
||||||
max-height: 75vh;
|
max-height: 75vh;
|
||||||
scroll-margin-top: 0;
|
scroll-margin-top: 0;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
@ -106,15 +100,12 @@
|
|||||||
import { debounce, strptime_vista } from './util.mjs';
|
import { debounce, strptime_vista } from './util.mjs';
|
||||||
|
|
||||||
import Subtitle from './Subtitle.vue';
|
import Subtitle from './Subtitle.vue';
|
||||||
import ViewDocNew from './ViewDocNew.vue';
|
|
||||||
import ViewDocView from './ViewDocView.vue';
|
|
||||||
import ModalPromptSignatureCode from './ModalPromptSignatureCode.vue';
|
|
||||||
|
|
||||||
const SZ_WINDOW = 100;
|
const SZ_WINDOW = 100;
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
Subtitle, ViewDocNew, ViewDocView, ModalPromptSignatureCode
|
Subtitle
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
client: Object,
|
client: Object,
|
||||||
@ -127,19 +118,13 @@
|
|||||||
dfn: null,
|
dfn: null,
|
||||||
has_more: '',
|
has_more: '',
|
||||||
is_loading: false,
|
is_loading: false,
|
||||||
rs_unsigned: [],
|
resultset: [],
|
||||||
rs_signed: [],
|
|
||||||
selection: null,
|
selection: null,
|
||||||
show_signature: false,
|
selection_text: null,
|
||||||
observer_scroller: null,
|
observer_scroller: null,
|
||||||
observer_viewport: null
|
observer_viewport: null
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
|
||||||
resultset() {
|
|
||||||
return this.rs_unsigned.concat(this.rs_signed);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
watch: {
|
watch: {
|
||||||
'$route.params.tiu_da': {
|
'$route.params.tiu_da': {
|
||||||
async handler(value) {
|
async handler(value) {
|
||||||
@ -155,6 +140,17 @@
|
|||||||
datetimestring(date) {
|
datetimestring(date) {
|
||||||
return date.toLocaleDateString('sv-SE') + ' ' + date.toLocaleTimeString('en-GB');
|
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() {
|
async load_more() {
|
||||||
try {
|
try {
|
||||||
this.is_loading = true;
|
this.is_loading = true;
|
||||||
@ -162,7 +158,7 @@
|
|||||||
if(this.dfn != this.patient_dfn) {
|
if(this.dfn != this.patient_dfn) {
|
||||||
this.dfn = this.patient_dfn;
|
this.dfn = this.patient_dfn;
|
||||||
this.has_more = '';
|
this.has_more = '';
|
||||||
this.rs_signed = [];
|
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);
|
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)) {
|
if((res) && (res.length > 0)) {
|
||||||
@ -172,88 +168,44 @@
|
|||||||
this.has_more = last.IEN;
|
this.has_more = last.IEN;
|
||||||
res.splice(res.length - 1, 1);
|
res.splice(res.length - 1, 1);
|
||||||
}
|
}
|
||||||
if(this.rs_signed.length > 0) Array.prototype.push.apply(this.rs_signed, res);
|
if(this.resultset.length > 0) Array.prototype.push.apply(this.resultset, res);
|
||||||
else this.rs_signed = res;
|
else this.resultset = res;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.dfn = null;
|
this.dfn = null;
|
||||||
this.has_more = '';
|
this.has_more = '';
|
||||||
this.rs_signed = [];
|
this.resultset = [];
|
||||||
}
|
}
|
||||||
} catch(ex) {
|
} catch(ex) {
|
||||||
console.warn(ex);
|
console.warn(ex);
|
||||||
} finally {
|
} finally {
|
||||||
this.is_loading = false;
|
this.is_loading = false;
|
||||||
}
|
}
|
||||||
},
|
|
||||||
async load_unsigned() {
|
|
||||||
this.rs_unsigned = [];
|
|
||||||
this.rs_unsigned = await client.TIU_DOCUMENTS_BY_CONTEXT(3, 2, this.patient_dfn, 0, 0, 0, 0, 'D', 1, 0, 1, '');
|
|
||||||
},
|
|
||||||
async reload() {
|
|
||||||
this.dfn = null;
|
|
||||||
await client.TIU_DOCUMENTS_BY_CONTEXT_FLUSH(3, 2, this.patient_dfn, 0, 0, 0, 0, 'D', 1, 0, 1, '');
|
|
||||||
await this.load_unsigned();
|
|
||||||
await client.TIU_DOCUMENTS_BY_CONTEXT_FLUSH(3, 1, this.patient_dfn, -1, -1, 0, SZ_WINDOW, 'D', 1, 0, 1, '');
|
|
||||||
await this.load_more();
|
|
||||||
},
|
|
||||||
async doc_create(params) {
|
|
||||||
var vstr = params.location.datetime ? ('' + params.location.IEN + ';' + params.location.datetime + ';A') : ('' + params.location.IEN + ';' + params.datetime + ';E');
|
|
||||||
var res = await this.client.TIU_CREATE_RECORD(this.patient_dfn, params.title, '', '', '', { '".01"': params.title, '"1202"': params.author, '"1301"': params.datetime, '"1205"': params.location.IEN }, vstr, '1');
|
|
||||||
if(res) {
|
|
||||||
this.reload();
|
|
||||||
this.$router.replace({ path: '/patient/' + this.patient_dfn + '/document/' + res, query: { edit: '' } });
|
|
||||||
} else {
|
|
||||||
console.error('Unable to create document', params, res);
|
|
||||||
window.alert('Unable to create document.');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
doc_sign_prompt(ien) {
|
|
||||||
this.show_signature = true;
|
|
||||||
},
|
|
||||||
async doc_sign(code) {
|
|
||||||
var selection = this.selection;
|
|
||||||
if((selection) & (code)) {
|
|
||||||
this.show_signature = false;
|
|
||||||
await this.client.TIU_SIGN_RECORD(selection, ' ' + code + ' ');
|
|
||||||
this.reload();
|
|
||||||
this.selection = null;
|
|
||||||
await this.$nextTick();
|
|
||||||
this.selection = selection;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async doc_delete(ien) {
|
|
||||||
if(window.confirm('Delete this document?')) {
|
|
||||||
var vstr = await this.client.ORWPCE_NOTEVSTR(ien);
|
|
||||||
if(vstr) await this.client.ORWPCE_DELETE(vstr, this.patient_dfn);
|
|
||||||
await this.client.TIU_DELETE_RECORD(ien);
|
|
||||||
this.reload();
|
|
||||||
if(this.selection == ien) {
|
|
||||||
this.selection = null;
|
|
||||||
this.$router.replace({ path: '/patient/' + this.patient_dfn + '/document' });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.$watch(
|
this.$watch(
|
||||||
() => (this.client, this.patient_dfn, {}),
|
() => (this.client, this.patient_dfn, {}),
|
||||||
debounce(() => { this.load_more(); this.load_unsigned(); }, 500),
|
debounce(this.load_more, 500),
|
||||||
{ immediate: true }
|
{ immediate: true }
|
||||||
);
|
);
|
||||||
this.$watch(
|
this.$watch(
|
||||||
() => (this.client, this.selection, {}),
|
() => (this.client, this.selection, {}),
|
||||||
async function() {
|
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);
|
||||||
|
}
|
||||||
if(this.$refs.scroller) {
|
if(this.$refs.scroller) {
|
||||||
if(this.selection) { // scroll to selected item
|
if(this.selection_text) { // scroll to selected item
|
||||||
if(this.selection != 'new') {
|
await this.$nextTick();
|
||||||
await this.$nextTick();
|
var active = this.$refs.scroller.querySelectorAll(':scope > .active');
|
||||||
var active = this.$refs.scroller.querySelectorAll(':scope > .active');
|
if(active.length > 0) (Element.prototype.scrollIntoViewIfNeeded || Element.prototype.scrollIntoView).call(active[0]);
|
||||||
if(active.length > 0) (Element.prototype.scrollIntoViewIfNeeded || Element.prototype.scrollIntoView).call(active[0]);
|
if(this.$refs.detail) { // scroll to top of detail panel
|
||||||
if(this.$refs.detail) { // scroll to top of detail panel
|
this.$refs.detail.scrollIntoView();
|
||||||
this.$refs.detail.scrollIntoView();
|
this.$refs.detail.scrollTop = 0;
|
||||||
this.$refs.detail.scrollTop = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else { // scroll to topmost item
|
} else { // scroll to topmost item
|
||||||
var offset = this.$refs.scroller.getBoundingClientRect().top;
|
var offset = this.$refs.scroller.getBoundingClientRect().top;
|
||||||
@ -272,9 +224,9 @@
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.observer_scroller = new IntersectionObserver(([entry]) => { if((entry.isIntersecting) && (this.selection) && (this.has_more) && (!this.is_loading)) this.load_more(); }, { root: this.$refs.scroller, rootMargin: '25%' });
|
this.observer_scroller = new IntersectionObserver(([entry]) => { if((entry.isIntersecting) && (this.selection_text) && (this.has_more) && (!this.is_loading)) this.load_more(); }, { root: this.$refs.scroller, rootMargin: '25%' });
|
||||||
this.observer_scroller.observe(this.$refs.bottom);
|
this.observer_scroller.observe(this.$refs.bottom);
|
||||||
this.observer_viewport = new IntersectionObserver(([entry]) => { if((entry.isIntersecting) && (!this.selection) && (this.has_more) && (!this.is_loading)) this.load_more(); }, { rootMargin: '25%' });
|
this.observer_viewport = new IntersectionObserver(([entry]) => { if((entry.isIntersecting) && (!this.selection_text) && (this.has_more) && (!this.is_loading)) this.load_more(); }, { rootMargin: '25%' });
|
||||||
this.observer_viewport.observe(this.$refs.bottom);
|
this.observer_viewport.observe(this.$refs.bottom);
|
||||||
},
|
},
|
||||||
destroyed() {
|
destroyed() {
|
||||||
|
@ -1,177 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div v-if="record !== null" class="card mb-3 shadow">
|
|
||||||
<div class="card-header d-flex justify-content-between align-items-center">
|
|
||||||
<span>{{record['~.01'] && record['~.01'].description || 'Document'}}</span>
|
|
||||||
<a class="widget" @click="() => update(true)">✔</a>
|
|
||||||
</div>
|
|
||||||
<ul class="list-group list-group-flush">
|
|
||||||
<li class="list-group-item"><DateTimePicker v-model="datetime" /></li>
|
|
||||||
<li class="list-group-item">
|
|
||||||
<div class="input-group">
|
|
||||||
<span class="input-group-text">Subject</span>
|
|
||||||
<input type="text" class="form-control" v-model="subject" />
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li class="list-group-item"><textarea ref="textarea" class="form-control" v-model="text" @keydown.tab.exact.prevent="tab" @keydown.shift.tab.exact.prevent="untab" /></li>
|
|
||||||
</ul>
|
|
||||||
<div v-if="saved" class="card-footer" style="text-align: right;">Saved at {{saved.toLocaleString()}}</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
a.widget {
|
|
||||||
cursor: default;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
textarea {
|
|
||||||
font-family: monospace;
|
|
||||||
tab-size: 8;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { debounce } from './util.mjs';
|
|
||||||
import { strptime, strftime } from './fmdatetime.mjs';
|
|
||||||
|
|
||||||
import DateTimePicker from './DateTimePicker.vue';
|
|
||||||
|
|
||||||
function untab({ input, size=8, tab='\t', space=' ', join=true}={}) {
|
|
||||||
input = input.split('\n');
|
|
||||||
for(var i = input.length - 1; i >= 0; --i) input[i] = untab_line(input[i], size, tab, space);
|
|
||||||
return join ? input.join('\n') : input;
|
|
||||||
}
|
|
||||||
function untab_line(line, size=8, tab='\t', space=' ') {
|
|
||||||
var res = '', index = 0, offset = 0, next, count;
|
|
||||||
while((next = line.indexOf(tab, index)) >= 0) {
|
|
||||||
count = size - (next + offset)%size;
|
|
||||||
res += line.substring(index, next) + Array(count + 1).join(space);
|
|
||||||
offset += count - 1;
|
|
||||||
index = next + 1;
|
|
||||||
}
|
|
||||||
return res + line.substring(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
function retab({ input, size=8, tab='\t', space=' ' }={}) {
|
|
||||||
var re_space = new RegExp(space.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + '+', 'g');
|
|
||||||
return input.replace(re_space, function(m) { return Array(Math.ceil(m.length/size) + 1).join(tab); });
|
|
||||||
}
|
|
||||||
|
|
||||||
function wrap({ input, width=80, cut=false, tabsize=8, tab='\t', space=' ', untab=false, join=true }={}) {
|
|
||||||
var input = input.split('\n'), lines, res = [];
|
|
||||||
if(untab) {
|
|
||||||
for(var i = 0; i < input.length; ++i) {
|
|
||||||
lines = wrap_line_split(untab_line(input[i], tabsize, tab, space), width, cut);
|
|
||||||
for(var j = 0; j < lines.length; ++j) res.push(lines[j].replace(/(\s)\s+$/, '$1'));
|
|
||||||
}
|
|
||||||
return join ? res.join('\n') : res;
|
|
||||||
} else {
|
|
||||||
for(var i = 0; i < input.length; ++i) {
|
|
||||||
lines = wrap_line_split(untab_line(input[i], tabsize, tab, tab), width, cut); // replace tabs with placeholder tabs
|
|
||||||
for(var j = 0; j < lines.length; ++j) res.push(lines[j].replace(/(\s)\s+$/, '$1'));
|
|
||||||
}
|
|
||||||
res = retab({ input: res.join('\n'), size: tabsize, tab, space: tab }); // collapse placeholder tabs
|
|
||||||
return join ? res : res.split('\n');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function wrap_line(str, width=80, cut=false, brk='\n') {
|
|
||||||
if(!str) return str;
|
|
||||||
return str.match(new RegExp('.{1,' + width + '}(\\s+|$)' + (cut ? '|.{' + width + '}|.+$' : '|\\S+?(\\s+|$)'), 'g')).join(brk);
|
|
||||||
}
|
|
||||||
function wrap_line_split(str, width=80, cut=false) {
|
|
||||||
if(!str) return [str];
|
|
||||||
return str.match(new RegExp('.{1,' + width + '}(\\s+|$)' + (cut ? '|.{' + width + '}|.+$' : '|\\S+?(\\s+|$)'), 'g'));
|
|
||||||
}
|
|
||||||
|
|
||||||
export default {
|
|
||||||
components: {
|
|
||||||
DateTimePicker
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
client: Object,
|
|
||||||
dfn: String,
|
|
||||||
ien: String
|
|
||||||
},
|
|
||||||
emits: {
|
|
||||||
'accept': null,
|
|
||||||
'update': Object
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
record: null,
|
|
||||||
saved: null
|
|
||||||
};
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
datetime: {
|
|
||||||
get() { return this.record && this.record['~1301'] && this.record['~1301'].value; },
|
|
||||||
set(value) { this.record['~1301'].value = strftime(strptime(value)); this.autosave(); }
|
|
||||||
},
|
|
||||||
subject: {
|
|
||||||
get() { return this.record && this.record['~1701'] && this.record['~1701'].value; },
|
|
||||||
set(value) { this.record['~1701'].value = this.record['~.07'].value = value; this.autosave(); }
|
|
||||||
},
|
|
||||||
text: {
|
|
||||||
get() { return this.record && this.record.text; },
|
|
||||||
set(value) { this.record.text = value; this.autosave(); }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
text() {
|
|
||||||
this.resize();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
async tab(evt) {
|
|
||||||
var target = event.target, value = target.value, start = target.selectionStart, end = target.selectionEnd;
|
|
||||||
if(start == end) document.execCommand('insertText', false, '\t');
|
|
||||||
else {
|
|
||||||
start = target.selectionStart = value.lastIndexOf('\n', start - 1) + 1;
|
|
||||||
end = target.selectionEnd = value.indexOf('\n', end); if(end < 0) end = value.length;
|
|
||||||
var selection = value.substring(start, end);
|
|
||||||
document.execCommand('insertText', false, selection.replace(/^/gm, '\t'));
|
|
||||||
await this.$nextTick();
|
|
||||||
target.selectionStart = start;
|
|
||||||
target.selectionEnd = end + selection.split('\n').length;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async untab(evt) {
|
|
||||||
var target = event.target, value = target.value;
|
|
||||||
var start = target.selectionStart = value.lastIndexOf('\n', target.selectionStart - 1) + 1;
|
|
||||||
var end = target.selectionEnd = value.indexOf('\n', target.selectionEnd); if(end < 0) end = value.length;
|
|
||||||
var selection = value.substring(start, end);
|
|
||||||
document.execCommand('insertText', false, selection.replace(/^\t/gm, ''));
|
|
||||||
await this.$nextTick();
|
|
||||||
target.selectionStart = start;
|
|
||||||
target.selectionEnd = end - (selection.match(/^\t/gm) || []).length;
|
|
||||||
},
|
|
||||||
async update(accept) {
|
|
||||||
var res = this.record.reduce((acc, val) => (acc['"' + val.field + '"'] = val.value, acc), {});
|
|
||||||
var text = wrap({input: this.text || '\x01', width: 80, cut: true, untab: false, join: false});
|
|
||||||
for(var i = 0; i < text.length; ++i) res['"TEXT","' + (i + 1) + '","0"'] = text[i];
|
|
||||||
this.$emit('update', res);
|
|
||||||
if(await this.client.TIU_UPDATE_RECORD(this.ien, res, 0)) {
|
|
||||||
await this.client.TIU_GET_RECORD_TEXT_FLUSH(this.ien);
|
|
||||||
this.saved = new Date();
|
|
||||||
if(accept) this.$emit('accept');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
created() {
|
|
||||||
this.resize = debounce(async function() {
|
|
||||||
var textarea = this.$refs.textarea;
|
|
||||||
textarea.style.height = 'auto';
|
|
||||||
await this.$nextTick();
|
|
||||||
textarea.style.height = textarea.scrollHeight + 4 + 'px';
|
|
||||||
}, 50);
|
|
||||||
this.autosave = debounce(this.update, 2000);
|
|
||||||
this.$watch(
|
|
||||||
() => (this.client, this.ien, {}),
|
|
||||||
async function() {
|
|
||||||
this.record = (this.client) && (this.ien) ? await this.client.TIU_LOAD_RECORD_FOR_EDIT(this.ien, '.01;.06;.07;1301;1204;1208;1701;1205;1405;2101;70201;70202') : [];
|
|
||||||
this.resize();
|
|
||||||
},
|
|
||||||
{ immediate: true }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
|
@ -1,79 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="card mb-3 shadow">
|
|
||||||
<div class="card-header d-flex justify-content-between align-items-center">
|
|
||||||
<span>New document</span>
|
|
||||||
<a class="close" @click="() => $emit('cancel')">❌</a>
|
|
||||||
</div>
|
|
||||||
<ul class="list-group list-group-flush">
|
|
||||||
<li class="list-group-item"><ViewLocationLookup :client="client" :dfn="dfn" label="Visit" v-model="x_location" /></li>
|
|
||||||
<li class="list-group-item"><ViewDocTitleLookup :client="client" label="Title" v-model="x_title" /></li>
|
|
||||||
<li class="list-group-item"><ViewUserLookup :client="client" label="Author" v-model="x_author" /></li>
|
|
||||||
<li class="list-group-item"><DateTimePicker v-model="x_datetime" /></li>
|
|
||||||
</ul>
|
|
||||||
<div class="card-footer btn-group" role="group"><button class="btn btn-primary" :disabled="!((x_location) && (x_location.IEN) && (x_title) && (x_author))" @click="() => $emit('submit', { location: x_location, title: x_title, author: x_author, datetime: fmdatetime(x_datetime) })">Create</button></div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
a.close {
|
|
||||||
cursor: default;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { strptime, strftime } from './fmdatetime.mjs';
|
|
||||||
|
|
||||||
import ViewLocationLookup from './ViewLocationLookup.vue';
|
|
||||||
import ViewDocTitleLookup from './ViewDocTitleLookup.vue';
|
|
||||||
import ViewUserLookup from './ViewUserLookup.vue';
|
|
||||||
import DateTimePicker from './DateTimePicker.vue';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
components: {
|
|
||||||
ViewLocationLookup, ViewDocTitleLookup, ViewUserLookup, DateTimePicker
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
client: Object,
|
|
||||||
dfn: String,
|
|
||||||
location: String,
|
|
||||||
title: String,
|
|
||||||
author: String,
|
|
||||||
datetime: {
|
|
||||||
type: String,
|
|
||||||
default: 'N'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
emits: {
|
|
||||||
'cancel': null,
|
|
||||||
'submit': Object,
|
|
||||||
'update:location': String,
|
|
||||||
'update:title': String,
|
|
||||||
'update:author': String,
|
|
||||||
'update:datetime': String
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
x_location: this.location,
|
|
||||||
x_title: this.title,
|
|
||||||
x_author: this.author,
|
|
||||||
x_datetime: this.datetime
|
|
||||||
};
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
location(value) { this.x_location = value; },
|
|
||||||
x_location(value) { this.$emit('update:location', value); },
|
|
||||||
title(value) { this.x_title = value; },
|
|
||||||
x_title(value) { this.$emit('update:title', value); },
|
|
||||||
author(value) { this.x_author = value; },
|
|
||||||
x_author(value) { this.$emit('update:author', value); },
|
|
||||||
datetime(value) { this.x_datetime = value; },
|
|
||||||
x_datetime(value) { this.$emit('update:datetime', value); }
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
fmdatetime(datetime) {
|
|
||||||
return strftime(strptime(datetime));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
|
@ -1,123 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div v-if="label" class="input-group">
|
|
||||||
<span class="input-group-text">{{label}}</span>
|
|
||||||
<input class="form-control" placeholder="Filter..." v-model="x_query" />
|
|
||||||
</div>
|
|
||||||
<input v-else class="form-control" placeholder="Filter..." v-model="x_query" />
|
|
||||||
<div class="scroller" ref="scroller">
|
|
||||||
<table class="table table-striped">
|
|
||||||
<tbody>
|
|
||||||
<tr v-for="item in resultset" :class="{ 'table-active': item.IEN == x_modelValue }" @click="x_modelValue = item.IEN">
|
|
||||||
<td>{{item.name}}</td>
|
|
||||||
<td style="text-align: right;">#{{item.IEN}}</td>
|
|
||||||
</tr>
|
|
||||||
<tr ref="bottom" />
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
div.scroller {
|
|
||||||
max-height: 25vh;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
td {
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
.table-active, .table-active:nth-of-type(odd) > * {
|
|
||||||
color: #fff;
|
|
||||||
background-color: #0d6efd;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { debounce } from './util.mjs';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
props: {
|
|
||||||
client: Object,
|
|
||||||
label: String,
|
|
||||||
query: String,
|
|
||||||
modelValue: String
|
|
||||||
},
|
|
||||||
emits: {
|
|
||||||
'update:query': String,
|
|
||||||
'update:modelValue': String
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
resultset: [],
|
|
||||||
has_more: false,
|
|
||||||
is_loading: true,
|
|
||||||
observer_bottom: null,
|
|
||||||
x_query: this.query,
|
|
||||||
x_modelValue: this.modelValue
|
|
||||||
};
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
query_view() {
|
|
||||||
return this.x_query ? this.x_query.replace(/^\s+|\s+$/g, '').replace(/\s+/g, ' ').toUpperCase() : '';
|
|
||||||
}
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
modelValue(value) { this.x_modelValue = value; },
|
|
||||||
x_modelValue(value) { this.$emit('update:modelValue', value); },
|
|
||||||
query(value) { this.x_query = value; },
|
|
||||||
x_query(value) { this.$emit('update:query', value); }
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
async handle_bottom([entry]) {
|
|
||||||
if((entry.isIntersecting) && (this.has_more) && (!this.is_loading)) {
|
|
||||||
this.is_loading = true;
|
|
||||||
this.has_more = false;
|
|
||||||
try {
|
|
||||||
var batch = await this.client.TIU_LONG_LIST_OF_TITLES(3, this.resultset[this.resultset.length - 1].name, 1);
|
|
||||||
if(this.query_view.length >= 1) batch = batch.filter(x => x.name.startsWith(this.query_view));
|
|
||||||
if(batch.length > 0) {
|
|
||||||
Array.prototype.push.apply(this.resultset, batch);
|
|
||||||
this.has_more = true;
|
|
||||||
} else this.has_more = false;
|
|
||||||
} catch(ex) {
|
|
||||||
this.has_more = false;
|
|
||||||
} finally {
|
|
||||||
this.is_loading = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
created() {
|
|
||||||
this.$watch(
|
|
||||||
() => (this.client, this.query_view, {}),
|
|
||||||
debounce(async function() {
|
|
||||||
if(this.client) {
|
|
||||||
this.is_loading = true;
|
|
||||||
this.has_more = false;
|
|
||||||
try {
|
|
||||||
var query = this.query_view;
|
|
||||||
if(query.length >= 1) {
|
|
||||||
var batch = await this.client.TIU_LONG_LIST_OF_TITLES(3, query.slice(0, -1) + String.fromCharCode(query.charCodeAt(query.length - 1) - 1) + '~', 1);
|
|
||||||
this.resultset = batch.filter(x => x.name.startsWith(query));
|
|
||||||
} else this.resultset = await this.client.TIU_LONG_LIST_OF_TITLES(3, '', 1);
|
|
||||||
this.has_more = this.resultset.length > 0;
|
|
||||||
} catch(ex) {
|
|
||||||
this.resultset = [];
|
|
||||||
this.has_more = false;
|
|
||||||
} finally {
|
|
||||||
this.is_loading = false;
|
|
||||||
if(this.$refs.scroller) this.$refs.scroller.scrollTo(0, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, 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>
|
|
@ -1,98 +0,0 @@
|
|||||||
<template>
|
|
||||||
<ViewDocEdit v-if="(can_edit) && (is_editing)" :client="client" :dfn="dfn" :ien="ien" @update="x => $emit('update', x)" @accept="doc_accept" />
|
|
||||||
<div v-else class="card mb-3 shadow">
|
|
||||||
<div class="card-header d-flex justify-content-between align-items-center">
|
|
||||||
<span>{{localtitle || 'Document'}}</span>
|
|
||||||
<span>
|
|
||||||
<a v-if="can_delete" class="widget" @click="() => $emit('delete', ien)">🗑</a>
|
|
||||||
<a v-if="can_edit" class="widget" @click="() => is_editing = true">✏</a>
|
|
||||||
<a v-if="can_sign" class="widget" @click="() => $emit('sign', ien)">🔏</a>
|
|
||||||
<a class="widget" @click="() => $emit('cancel')">❌</a>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div class="card-body">{{text}}</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
a.widget {
|
|
||||||
cursor: default;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
div.card-body {
|
|
||||||
tab-size: 8;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import ViewDocEdit from './ViewDocEdit.vue';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
components: {
|
|
||||||
ViewDocEdit
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
client: Object,
|
|
||||||
dfn: String,
|
|
||||||
ien: String,
|
|
||||||
},
|
|
||||||
emits: {
|
|
||||||
'cancel': null,
|
|
||||||
'sign': null,
|
|
||||||
'update': Object,
|
|
||||||
'delete': String
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
text: null,
|
|
||||||
can_sign: null,
|
|
||||||
can_edit: null,
|
|
||||||
can_delete: null
|
|
||||||
};
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
is_editing: {
|
|
||||||
get() { return this.$route.query.hasOwnProperty('edit'); },
|
|
||||||
set(value) {
|
|
||||||
var query = { ...this.$route.query };
|
|
||||||
if(value) query.edit = '';
|
|
||||||
else delete query.edit;
|
|
||||||
this.$router.replace({ query });
|
|
||||||
}
|
|
||||||
},
|
|
||||||
localtitle() {
|
|
||||||
var doc = this.text;
|
|
||||||
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, '');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
async doc_accept() {
|
|
||||||
this.text = await this.client.TIU_GET_RECORD_TEXT(this.ien);
|
|
||||||
this.is_editing = false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
created() {
|
|
||||||
this.$watch(
|
|
||||||
() => (this.client, this.ien, {}),
|
|
||||||
async function() {
|
|
||||||
this.text = this.can_edit = this.can_delete = null;
|
|
||||||
if((this.client) && (this.ien)) {
|
|
||||||
this.text = await this.client.TIU_GET_RECORD_TEXT(this.ien);
|
|
||||||
this.can_sign = (await this.client.TIU_AUTHORIZATION(this.ien, 'SIGNATURE') == '1') || (await this.client.TIU_AUTHORIZATION(this.ien, 'COSIGNATURE') == '1');
|
|
||||||
this.can_edit = await this.client.TIU_AUTHORIZATION(this.ien, 'EDIT RECORD') == '1';
|
|
||||||
this.can_delete = await this.client.TIU_AUTHORIZATION(this.ien, 'DELETE RECORD') == '1';
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ immediate: true }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
|
@ -40,7 +40,7 @@
|
|||||||
methods: {
|
methods: {
|
||||||
async submit(payload) {
|
async submit(payload) {
|
||||||
if((this.ien) && (this.dfn) && (payload)) {
|
if((this.ien) && (this.dfn) && (payload)) {
|
||||||
var user_ien = (await this.client.authinfo()).duz;
|
var user_ien = (await this.client.userinfo()).result[0];
|
||||||
var dgrp = await this.client.ORWDX_DGRP(this.dlgname.BaseDialogName);
|
var dgrp = await this.client.ORWDX_DGRP(this.dlgname.BaseDialogName);
|
||||||
var res = await client.ORWDX_SAVE(this.dfn, 0/*user_ien*/, 0/*location_ien*/, this.dlgname.BaseDialogName, dgrp, this.dlgname.BaseDialogIEN, ''/*order_ifn*/, payload, '', '', '', 0);
|
var res = await client.ORWDX_SAVE(this.dfn, 0/*user_ien*/, 0/*location_ien*/, this.dlgname.BaseDialogName, dgrp, this.dlgname.BaseDialogIEN, ''/*order_ifn*/, payload, '', '', '', 0);
|
||||||
console.log(res);
|
console.log(res);
|
||||||
@ -52,8 +52,8 @@
|
|||||||
() => (this.client, this.ien, {}),
|
() => (this.client, this.ien, {}),
|
||||||
async () => {
|
async () => {
|
||||||
if((this.client) && (this.ien)) {
|
if((this.client) && (this.ien)) {
|
||||||
var authinfo = await this.client.authinfo();
|
var userinfo = await this.client.userinfo();
|
||||||
var user_ien = authinfo && authinfo.success ? authinfo.duz : '';
|
var user_ien = userinfo && userinfo.result ? userinfo.result[0] : '';
|
||||||
this.dlgname = await this.client.ORWDXM_DLGNAME(this.ien);
|
this.dlgname = await this.client.ORWDXM_DLGNAME(this.ien);
|
||||||
if(this.dlgname.BaseDialogIEN != this.ien) console.warn('IEN =', this.ien, '|', 'BaseDialogIEN =', this.dlgname.BaseDialogIEN);
|
if(this.dlgname.BaseDialogIEN != this.ien) console.warn('IEN =', this.ien, '|', 'BaseDialogIEN =', this.dlgname.BaseDialogIEN);
|
||||||
this.dlgdef = await this.client.ORWDX_DLGDEF(this.dlgname.BaseDialogName);
|
this.dlgdef = await this.client.ORWDX_DLGDEF(this.dlgname.BaseDialogName);
|
||||||
|
@ -1,131 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div v-if="label" class="input-group">
|
|
||||||
<span class="input-group-text">{{label}}</span>
|
|
||||||
<input class="form-control" placeholder="Filter..." v-model="x_query" />
|
|
||||||
</div>
|
|
||||||
<input v-else class="form-control" placeholder="Filter..." v-model="x_query" />
|
|
||||||
<div class="scroller" ref="scroller">
|
|
||||||
<table class="table table-striped">
|
|
||||||
<tbody>
|
|
||||||
<tr v-for="item in resultset" :class="{ 'table-active': item.DUZ == x_modelValue }" @click="x_modelValue = item.DUZ">
|
|
||||||
<td>{{item.name}}</td>
|
|
||||||
<td>{{item.description.replace(/^-\s*/g, '')}}</td>
|
|
||||||
<td style="text-align: right;">#{{item.DUZ}}</td>
|
|
||||||
</tr>
|
|
||||||
<tr ref="bottom" />
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
div.scroller {
|
|
||||||
max-height: 25vh;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
td {
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
.table-active, .table-active:nth-of-type(odd) > * {
|
|
||||||
color: #fff;
|
|
||||||
background-color: #0d6efd;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { debounce } from './util.mjs';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
props: {
|
|
||||||
client: Object,
|
|
||||||
label: String,
|
|
||||||
query: String,
|
|
||||||
modelValue: String
|
|
||||||
},
|
|
||||||
emits: {
|
|
||||||
'update:query': String,
|
|
||||||
'update:modelValue': String
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
resultset: [],
|
|
||||||
has_more: false,
|
|
||||||
is_loading: true,
|
|
||||||
observer_bottom: null,
|
|
||||||
x_query: this.query,
|
|
||||||
x_modelValue: this.modelValue
|
|
||||||
};
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
query_view() {
|
|
||||||
return this.x_query ? this.x_query.replace(/^\s+|\s+$/g, '').replace(/\s+/g, ' ').toUpperCase() : '';
|
|
||||||
}
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
modelValue(value) { this.x_modelValue = value; },
|
|
||||||
x_modelValue(value) { this.$emit('update:modelValue', value); },
|
|
||||||
query(value) { this.x_query = value; },
|
|
||||||
x_query(value) { this.$emit('update:query', value); }
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
async set_default() {
|
|
||||||
if(this.x_modelValue) return;
|
|
||||||
var userinfo = await this.client.XUS_GET_USER_INFO();
|
|
||||||
this.x_modelValue = userinfo[0];
|
|
||||||
this.x_query = userinfo[1]
|
|
||||||
},
|
|
||||||
async handle_bottom([entry]) {
|
|
||||||
if((entry.isIntersecting) && (this.has_more) && (!this.is_loading)) {
|
|
||||||
this.is_loading = true;
|
|
||||||
this.has_more = false;
|
|
||||||
try {
|
|
||||||
var batch = await this.client.ORWU_NEWPERS(this.resultset[this.resultset.length - 1].name, 1, '', '', '', '', '', '', 0);
|
|
||||||
if(this.query_view.length >= 1) batch = batch.filter(x => x.name.toUpperCase().startsWith(this.query_view));
|
|
||||||
if(batch.length > 0) {
|
|
||||||
Array.prototype.push.apply(this.resultset, batch);
|
|
||||||
this.has_more = true;
|
|
||||||
} else this.has_more = false;
|
|
||||||
} catch(ex) {
|
|
||||||
this.has_more = false;
|
|
||||||
} finally {
|
|
||||||
this.is_loading = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
created() {
|
|
||||||
this.$watch(
|
|
||||||
() => (this.client, this.query_view, {}),
|
|
||||||
debounce(async function() {
|
|
||||||
if(this.client) {
|
|
||||||
this.is_loading = true;
|
|
||||||
this.has_more = false;
|
|
||||||
try {
|
|
||||||
var query = this.query_view;
|
|
||||||
if(query.length >= 1) {
|
|
||||||
var batch = await this.client.ORWU_NEWPERS(query.slice(0, -1) + String.fromCharCode(query.charCodeAt(query.length - 1) - 1) + '~', 1, '', '', '', '', '', '', 0);
|
|
||||||
this.resultset = batch.filter(x => x.name.toUpperCase().startsWith(query));
|
|
||||||
} else this.resultset = await this.client.ORWU_NEWPERS('', 1, '', '', '', '', '', '', 0);
|
|
||||||
this.has_more = this.resultset.length > 0;
|
|
||||||
} catch(ex) {
|
|
||||||
this.resultset = [];
|
|
||||||
this.has_more = false;
|
|
||||||
} finally {
|
|
||||||
this.is_loading = false;
|
|
||||||
if(this.$refs.scroller) this.$refs.scroller.scrollTo(0, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, 500),
|
|
||||||
{ immediate: true }
|
|
||||||
);
|
|
||||||
this.set_default();
|
|
||||||
},
|
|
||||||
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>
|
|
@ -217,7 +217,7 @@ export function TplFS(client, parent, desc) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TplFS.fromUser = async function(client, user_ien=null) {
|
TplFS.fromUser = async function(client, user_ien=null) {
|
||||||
if(!user_ien) user_ien = (await client.authinfo()).duz;
|
if(!user_ien) user_ien = (await client.userinfo()).result[0];
|
||||||
return new TplFS(client, null, (await client.TIU_TEMPLATE_GETPROOT(user_ien))[0]);
|
return new TplFS(client, null, (await client.TIU_TEMPLATE_GETPROOT(user_ien))[0]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -30,8 +30,8 @@ export async function serverinfo(cid) {
|
|||||||
})).json();
|
})).json();
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function authinfo(cid) {
|
export async function userinfo(cid) {
|
||||||
return await (await fetch('/v1/vista/' + cid + '/authinfo', {
|
return await (await fetch('/v1/vista/' + cid + '/userinfo', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: '{}'
|
body: '{}'
|
||||||
@ -47,5 +47,5 @@ export async function authenticate(cid, avcode=null) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default window.vista = {
|
export default window.vista = {
|
||||||
connect, close, call, serverinfo, authinfo, authenticate
|
connect, close, call, serverinfo, userinfo, authenticate
|
||||||
};
|
};
|
||||||
|
@ -48,8 +48,6 @@ export const d_parse_boolean = data => data != '0';
|
|||||||
export const d_parse_text = data => data !== '' ? data.join('\r\n') : data;
|
export const d_parse_text = data => data !== '' ? data.join('\r\n') : data;
|
||||||
export const d_parse_array = data => data !== '' ? data : [];
|
export const d_parse_array = data => data !== '' ? data : [];
|
||||||
|
|
||||||
export const d_parse_authinfo = data => data ? { duz: data[0] != '0' ? data[0] : null, device_lock: data[1] != '0', change_verify: data[2] != '0', message: data[3], reserved: data[4], greeting_lines: data[5], greeting: data.slice(6), success: (data[0] != '0') && (data[2] == '0') } : { success: false }
|
|
||||||
|
|
||||||
export const d_parse_orderdialogs = (data, columns=['IEN', 'windowFormId', 'displayGroupId', 'type', 'displayText']) => data.map(function(row) {
|
export const d_parse_orderdialogs = (data, columns=['IEN', 'windowFormId', 'displayGroupId', 'type', 'displayText']) => data.map(function(row) {
|
||||||
row = row.split('^');
|
row = row.split('^');
|
||||||
row = [...row[0].split(';'), row[1]];
|
row = [...row[0].split(';'), row[1]];
|
||||||
@ -189,20 +187,6 @@ export const d_parse_multireport = data => {
|
|||||||
return (res._ts = _ts, res);
|
return (res._ts = _ts, res);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const d_parse_tiurecordtiux = data => {
|
|
||||||
var res = {};
|
|
||||||
if(data.length < 1) return res;
|
|
||||||
var brk = data.indexOf('$TXT'), text = undefined;
|
|
||||||
if(brk >= 0) {
|
|
||||||
text = data.slice(brk + 1).join('\r\n');
|
|
||||||
data = data.slice(0, brk);
|
|
||||||
}
|
|
||||||
data = d_split(data, '^', 'field', 'value', 'description');
|
|
||||||
data = data.reduce((acc, val) => (acc['~' + val.field] = val, acc), data);
|
|
||||||
if(text) data.text = text;
|
|
||||||
return data;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const d_parse_tiudocumentlist = data => d_split(data, '^', 'IEN', 'title', 'time', 'patient', 'author', 'location', 'status', 'visit').map(row => {
|
export const d_parse_tiudocumentlist = data => d_split(data, '^', 'IEN', 'title', 'time', 'patient', 'author', 'location', 'status', 'visit').map(row => {
|
||||||
row.author = row.author ? d_split1(row.author, ';', 'IEN', 'byline', 'name') : null;
|
row.author = row.author ? d_split1(row.author, ';', 'IEN', 'byline', 'name') : null;
|
||||||
row.visit = row.visit ? d_split1(row.visit, ';', 'date', 'time') : null;
|
row.visit = row.visit ? d_split1(row.visit, ';', 'date', 'time') : null;
|
||||||
@ -256,11 +240,11 @@ export function Client(cid, secret) {
|
|||||||
return heartbeat = window.setInterval(this.XWB_IM_HERE, interval);
|
return heartbeat = window.setInterval(this.XWB_IM_HERE, interval);
|
||||||
}
|
}
|
||||||
this.serverinfo = () => vista.serverinfo(cid);
|
this.serverinfo = () => vista.serverinfo(cid);
|
||||||
this.authinfo = aflow(() => vista.authinfo(cid), d_unwrap, d_parse_authinfo);
|
this.userinfo = () => vista.userinfo(cid);
|
||||||
this.authenticate = aflow((avcode=null) => vista.authenticate(cid, avcode), d_unwrap, d_parse_authinfo);
|
this.authenticate = (avcode=null) => vista.authenticate(cid, avcode);
|
||||||
|
|
||||||
if(!localstate.encfs) localstate.encfs = tplfs_randpassword();
|
if(!localstate.encfs) localstate.encfs = tplfs_randpassword();
|
||||||
this.tplfs = async () => this._tplfs ? this._tplfs : (this._tplfs = await TplFS.fromUser(this, (await this.authinfo()).duz));
|
this.tplfs = async () => this._tplfs ? this._tplfs : (this._tplfs = await TplFS.fromUser(this, (await this.userinfo()).result[0]));
|
||||||
this.encfs = async () => this._encfs ? this._encfs : (this._encfs = await EncFS.fromPassword(await this.tplfs(), localstate.encfs));
|
this.encfs = async () => this._encfs ? this._encfs : (this._encfs = await EncFS.fromPassword(await this.tplfs(), localstate.encfs));
|
||||||
|
|
||||||
this.remotestate = reactive({});
|
this.remotestate = reactive({});
|
||||||
@ -325,24 +309,10 @@ export function Client(cid, secret) {
|
|||||||
this.TIU_TEMPLATE_LOCK = aflow((...args) => this.call({ method: 'TIU_TEMPLATE_LOCK', context: ['OR CPRS GUI CHART'], ttl: 0, stale: false }, ...args), d_log, d_unwrap);
|
this.TIU_TEMPLATE_LOCK = aflow((...args) => this.call({ method: 'TIU_TEMPLATE_LOCK', context: ['OR CPRS GUI CHART'], ttl: 0, stale: false }, ...args), d_log, d_unwrap);
|
||||||
this.TIU_TEMPLATE_UNLOCK = aflow((...args) => this.call({ method: 'TIU_TEMPLATE_UNLOCK', context: ['OR CPRS GUI CHART'], ttl: 0, stale: false }, ...args), d_log, d_unwrap);
|
this.TIU_TEMPLATE_UNLOCK = aflow((...args) => this.call({ method: 'TIU_TEMPLATE_UNLOCK', context: ['OR CPRS GUI CHART'], ttl: 0, stale: false }, ...args), d_log, d_unwrap);
|
||||||
this.TIU_DOCUMENTS_BY_CONTEXT = aflow((...args) => this.call({ method: 'TIU_DOCUMENTS_BY_CONTEXT', context: ['OR CPRS GUI CHART'], ttl: 60, stale: false }, ...args), d_log, d_unwrap, d_parse_array, d_parse_tiudocumentlist);
|
this.TIU_DOCUMENTS_BY_CONTEXT = aflow((...args) => this.call({ method: 'TIU_DOCUMENTS_BY_CONTEXT', context: ['OR CPRS GUI CHART'], ttl: 60, stale: false }, ...args), d_log, d_unwrap, d_parse_array, d_parse_tiudocumentlist);
|
||||||
this.TIU_DOCUMENTS_BY_CONTEXT_FLUSH = aflow((...args) => this.call({ method: 'TIU_DOCUMENTS_BY_CONTEXT', context: ['OR CPRS GUI CHART'], ttl: 0, stale: false }, ...args), d_log, d_unwrap, d_parse_array, d_parse_tiudocumentlist);
|
|
||||||
this.TIU_GET_RECORD_TEXT = aflow((...args) => this.call({ method: 'TIU_GET_RECORD_TEXT', context: ['OR CPRS GUI CHART'], ttl: 60, stale: false }, ...args), d_log, d_unwrap, d_parse_text);
|
this.TIU_GET_RECORD_TEXT = aflow((...args) => this.call({ method: 'TIU_GET_RECORD_TEXT', context: ['OR CPRS GUI CHART'], ttl: 60, stale: false }, ...args), d_log, d_unwrap, d_parse_text);
|
||||||
this.TIU_GET_RECORD_TEXT_FLUSH = aflow((...args) => this.call({ method: 'TIU_GET_RECORD_TEXT', context: ['OR CPRS GUI CHART'], ttl: 0, stale: false }, ...args), d_log, d_unwrap, d_parse_text);
|
|
||||||
this.TIU_LONG_LIST_OF_TITLES = memoized(aflow((...args) => this.call({ method: 'TIU_LONG_LIST_OF_TITLES', context: ['OR CPRS GUI CHART'], ttl: 86400, stale: true, ttl: 86400, stale: true }, ...args), d_log, d_unwrap, f_split('^', 'IEN', 'name')));
|
|
||||||
this.TIU_CREATE_RECORD = aflow((...args) => this.call({ method: 'TIU_CREATE_RECORD', context: ['OR CPRS GUI CHART'], ttl: 0, stale: false }, ...args), d_log, d_unwrap);
|
|
||||||
this.TIU_AUTHORIZATION = aflow((...args) => this.call({ method: 'TIU_AUTHORIZATION', context: ['OR CPRS GUI CHART'], ttl: 0, stale: false }, ...args), d_log, d_unwrap);
|
|
||||||
this.TIU_LOAD_RECORD_FOR_EDIT = aflow((...args) => this.call({ method: 'TIU_LOAD_RECORD_FOR_EDIT', context: ['OR CPRS GUI CHART'], ttl: 0, stale: false }, ...args), d_log, d_unwrap, d_parse_tiurecordtiux);
|
|
||||||
this.TIU_UPDATE_RECORD = aflow((...args) => this.call({ method: 'TIU_UPDATE_RECORD', context: ['OR CPRS GUI CHART'], ttl: 0, stale: false }, ...args), d_log, d_unwrap);
|
|
||||||
this.TIU_DELETE_RECORD = aflow((...args) => this.call({ method: 'TIU_DELETE_RECORD', context: ['OR CPRS GUI CHART'], ttl: 0, stale: false }, ...args), d_log, d_unwrap);
|
|
||||||
this.TIU_SIGN_RECORD = aflow((...args) => this.call({ method: 'TIU_SIGN_RECORD', context: ['OR CPRS GUI CHART'], ttl: 0, stale: false }, ...args), d_log, d_unwrap);
|
|
||||||
|
|
||||||
this.ORWPCE_NOTEVSTR = aflow((...args) => this.call({ method: 'ORWPCE_NOTEVSTR', context: ['OR CPRS GUI CHART'], ttl: 86400, stale: true }, ...args), d_log, d_unwrap);
|
|
||||||
this.ORWPCE_DELETE = aflow((...args) => this.call({ method: 'ORWPCE_DELETE', context: ['OR CPRS GUI CHART'], ttl: 0, stale: false }, ...args), d_log, d_unwrap);
|
|
||||||
|
|
||||||
this.ORWCV_VST = memoized(aflow((...args) => this.callctx(['OR CPRS GUI CHART'], 'ORWCV_VST', ...args), d_log, d_unwrap, f_split('^', 'apptinfo', 'datetime', 'location', 'status')));
|
this.ORWCV_VST = memoized(aflow((...args) => this.callctx(['OR CPRS GUI CHART'], 'ORWCV_VST', ...args), d_log, d_unwrap, f_split('^', 'apptinfo', 'datetime', 'location', 'status')));
|
||||||
|
|
||||||
this.ORWU_NEWPERS = memoized(aflow((...args) => this.call({ method: 'ORWU_NEWPERS', context: ['OR CPRS GUI CHART'], ttl: 86400, stale: true }, ...args), d_log, d_unwrap, f_split('^', 'DUZ', 'name', 'description')));
|
|
||||||
this.ORWU_VALIDSIG = memoized(aflow((...args) => this.call({ method: 'ORWU_VALIDSIG', context: ['OR CPRS GUI CHART'], ttl: 0, stale: false }, ...args), d_log, d_unwrap));
|
|
||||||
this.ORWU1_NEWLOC = memoized(aflow((...args) => this.callctx(['OR CPRS GUI CHART'], 'ORWU1_NEWLOC', ...args), d_log, d_unwrap, f_split('^', 'IEN', 'name')));
|
this.ORWU1_NEWLOC = memoized(aflow((...args) => this.callctx(['OR CPRS GUI CHART'], 'ORWU1_NEWLOC', ...args), d_log, d_unwrap, f_split('^', 'IEN', 'name')));
|
||||||
|
|
||||||
this.ORWDX_DGNM = memoized(aflow((...args) => this.callctx(['OR CPRS GUI CHART'], 'ORWDX_DGNM', ...args), d_log, d_unwrap));
|
this.ORWDX_DGNM = memoized(aflow((...args) => this.callctx(['OR CPRS GUI CHART'], 'ORWDX_DGNM', ...args), d_log, d_unwrap));
|
||||||
|
6
main.py
6
main.py
@ -92,11 +92,11 @@ def application():
|
|||||||
logger.exception(request.url)
|
logger.exception(request.url)
|
||||||
return jsonify_error(ex, id=request.json.get('id'))
|
return jsonify_error(ex, id=request.json.get('id'))
|
||||||
|
|
||||||
@app.post('/v1/vista/<cid>/authinfo')
|
@app.post('/v1/vista/<cid>/userinfo')
|
||||||
def cb_authinfo(cid):
|
def cb_userinfo(cid):
|
||||||
try:
|
try:
|
||||||
client = clients[cid]
|
client = clients[cid]
|
||||||
return jsonify_result(client._obj._auth, id=request.json.get('id'))
|
return jsonify_result(client._obj._user, id=request.json.get('id'))
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
logger.exception(request.url)
|
logger.exception(request.url)
|
||||||
return jsonify_error(ex, id=request.json.get('id'))
|
return jsonify_error(ex, id=request.json.get('id'))
|
||||||
|
16
rpc.py
16
rpc.py
@ -112,7 +112,7 @@ class ClientSync(object):
|
|||||||
self.recv_rpc_msg = recv_rpc_msg(self.sock)
|
self.recv_rpc_msg = recv_rpc_msg(self.sock)
|
||||||
self.lock = threading.Lock()
|
self.lock = threading.Lock()
|
||||||
self._server = { 'host': host, 'port': port }
|
self._server = { 'host': host, 'port': port }
|
||||||
self._auth = None
|
self._user = None
|
||||||
self.context = 'XUS SIGNON'
|
self.context = 'XUS SIGNON'
|
||||||
if TCPConnect and (res := self.TCPConnect(self.sock.getsockname()[0], '0', socket.gethostname())) != 'accept':
|
if TCPConnect and (res := self.TCPConnect(self.sock.getsockname()[0], '0', socket.gethostname())) != 'accept':
|
||||||
raise RPCExcInvalidResult('TCPConnect', self.sock.getsockname()[0], '0', socket.gethostname(), res)
|
raise RPCExcInvalidResult('TCPConnect', self.sock.getsockname()[0], '0', socket.gethostname(), res)
|
||||||
@ -144,11 +144,13 @@ class ClientSync(object):
|
|||||||
return res
|
return res
|
||||||
def authenticate(self, identity: str, *, context=('XUS SIGNON',)):
|
def authenticate(self, identity: str, *, context=('XUS SIGNON',)):
|
||||||
self._server.update(RecordServerInfo(*self('XUS SIGNON SETUP', '', '1', context=context))._asdict())
|
self._server.update(RecordServerInfo(*self('XUS SIGNON SETUP', '', '1', context=context))._asdict())
|
||||||
if identity.startswith('<?xml version="1.0"'):
|
if identity.startswith('<?xml version="1.0" encoding="UTF-8"?>'):
|
||||||
res = self('XUS ESSO VALIDATE', RPCType(tuple(identity[i:i+200] for i in range(0, len(identity), 200)), RPCType.GLOBAL))
|
res = self('XUS ESSO VALIDATE', RPCType(tuple(identity[i:i+200] for i in range(0, len(identity), 200)), RPCType.GLOBAL))
|
||||||
else:
|
else:
|
||||||
res = self('XUS AV CODE', XWBHash_encrypt(identity))
|
res = self('XUS AV CODE', XWBHash_encrypt(identity))
|
||||||
self._auth = res if res[0] != '0' else None
|
if res[0] == '0' or res[2] != '0':
|
||||||
|
raise RPCExcAuth(res[3], res)
|
||||||
|
self._user = res
|
||||||
return res
|
return res
|
||||||
def keepalive(self, interval=None, *, context=('XUS SIGNON',)):
|
def keepalive(self, interval=None, *, context=('XUS SIGNON',)):
|
||||||
import time
|
import time
|
||||||
@ -186,7 +188,7 @@ class ClientAsync(object):
|
|||||||
self.arecv_rpc_msg = arecv_rpc_msg(self.reader)
|
self.arecv_rpc_msg = arecv_rpc_msg(self.reader)
|
||||||
self.lock = asyncio.Lock()
|
self.lock = asyncio.Lock()
|
||||||
self._server = { 'host': host, 'port': port, 'info': None }
|
self._server = { 'host': host, 'port': port, 'info': None }
|
||||||
self._auth = None
|
self._user = None
|
||||||
self.context = 'XUS SIGNON'
|
self.context = 'XUS SIGNON'
|
||||||
if TCPConnect and (res := await self.TCPConnect(self.writer.get_extra_info('sockname')[0], '0', socket.gethostname())) != 'accept':
|
if TCPConnect and (res := await self.TCPConnect(self.writer.get_extra_info('sockname')[0], '0', socket.gethostname())) != 'accept':
|
||||||
raise RPCExcInvalidResult('TCPConnect', self.writer.get_extra_info('sockname')[0], '0', socket.gethostname(), res)
|
raise RPCExcInvalidResult('TCPConnect', self.writer.get_extra_info('sockname')[0], '0', socket.gethostname(), res)
|
||||||
@ -223,11 +225,13 @@ class ClientAsync(object):
|
|||||||
return res
|
return res
|
||||||
async def authenticate(self, identity: str, *, context=('XUS SIGNON',)):
|
async def authenticate(self, identity: str, *, context=('XUS SIGNON',)):
|
||||||
self._server.update(RecordServerInfo(*await self('XUS SIGNON SETUP', '', '1', context=context))._asdict())
|
self._server.update(RecordServerInfo(*await self('XUS SIGNON SETUP', '', '1', context=context))._asdict())
|
||||||
if identity.startswith('<?xml version="1.0"'):
|
if identity.startswith('<?xml version="1.0" encoding="UTF-8"?>'):
|
||||||
res = await self('XUS ESSO VALIDATE', RPCType(tuple(identity[i:i+200] for i in range(0, len(identity), 200)), RPCType.GLOBAL))
|
res = await self('XUS ESSO VALIDATE', RPCType(tuple(identity[i:i+200] for i in range(0, len(identity), 200)), RPCType.GLOBAL))
|
||||||
else:
|
else:
|
||||||
res = await self('XUS AV CODE', XWBHash_encrypt(identity))
|
res = await self('XUS AV CODE', XWBHash_encrypt(identity))
|
||||||
self._auth = res if res[0] != '0' else None
|
if res[0] == '0' or res[2] != '0':
|
||||||
|
raise RPCExcAuth(res[3], res)
|
||||||
|
self._user = res
|
||||||
return res
|
return res
|
||||||
async def keepalive(self, interval=None, *, context=('XUS SIGNON',)):
|
async def keepalive(self, interval=None, *, context=('XUS SIGNON',)):
|
||||||
interval = interval or 0.45*float((await self.XWB_GET_BROKER_INFO(context=context))[0])
|
interval = interval or 0.45*float((await self.XWB_GET_BROKER_INFO(context=context))[0])
|
||||||
|
Loading…
Reference in New Issue
Block a user