This commit is contained in:
Inshal 2024-06-11 00:05:46 +05:00
parent 3f33811956
commit 84a0dc7186
9 changed files with 1738 additions and 7 deletions

View File

@ -54,3 +54,5 @@ export const ADMIN_LAB_KIT_DELETE_API = MAIN_DOMAIN + "/api/admin/labkit-delete/
export const ADMIN_PATIENT_DETAIL_API = MAIN_DOMAIN + "/api/admin/patient-full-detail/"
export const ADMIN_PROVIDER_DETAIL_API = MAIN_DOMAIN + "/api/admin/telemed-full-detail/"
export const ADMIN_PATIENT_PROFILE_API = MAIN_DOMAIN + "/api/admin/get-question-builder/"

View File

@ -0,0 +1,66 @@
<script setup>
import { computed, defineProps, onBeforeMount, ref } from 'vue';
import typeJson from '../patients/type_parse.json';
const allTypes = ref(typeJson);
const props = defineProps({
type: {
type: String,
required: true,
},
value: {
type: String,
required: false,
},
})
const bgColor = ref(null)
const operator = {
c(obj, value) {
let keys = Object.keys(obj.values)
let prev = 0;
for (let key of keys) {
if (key > prev && key <= value) {
prev = key
}
}
return obj.values[prev]
},
e(obj, value) {
return obj.values[value]
},
}
const progressValue = ref(0); // Initialize progress value with 0
const finalValue = computed(() => {
const singleObject = allTypes.value[props.type];
// console.log('singleObject', singleObject)
if (operator[singleObject.type](singleObject, props.value) > 0 && operator[singleObject.type](singleObject, props.value) <= 33) {
bgColor.value = 'success'
}
if (operator[singleObject.type](singleObject, props.value) > 33 && operator[singleObject.type](singleObject, props.value) <= 50) {
bgColor.value = 'yellow'
}
if (operator[singleObject.type](singleObject, props.value) > 50 && operator[singleObject.type](singleObject, props.value) <= 80) {
bgColor.value = 'warning'
}
if (operator[singleObject.type](singleObject, props.value) > 80 && operator[singleObject.type](singleObject, props.value) <= 100) {
bgColor.value = 'red'
}
return operator[singleObject.type](singleObject, props.value)
})
onBeforeMount(async () => {
await new Promise(resolve => {
setTimeout(() => {
progressValue.value = finalValue.value;
resolve();
}, 500); // Simulating some delay, you can replace this with your actual async logic
});
});
</script>
<template>
<v-progress-linear :model-value="progressValue" :height="22" :color="bgColor"></v-progress-linear>
</template>

View File

@ -0,0 +1,525 @@
<script setup>
import { useRoute, useRouter } from 'vue-router';
import { useStore } from 'vuex';
import QuestionProgressBar from '../patients/QuestionProgressBar.vue';
import questionsJson from '../patients/questions_parse.json';
const router = useRouter()
const route = useRoute();
const store = useStore()
const questionsJsonData = ref(questionsJson)
const answers = ref(null)
const QuestionsAnswers = ref([]);
const username = ref(null);
const email = ref(null);
const phone = ref(null);
const address1 = ref(null);
const dob = ref(null);
const agePatient = ref(null);
const isMobile = ref(window.innerWidth <= 768);
const patientId = route.params.patient_id
onMounted(async () => {
const navbar = document.querySelector('.layout-navbar');
const callDiv = document.querySelector('.layout-page-content');
if (navbar) {
navbar.style.display = 'block';
}
if (callDiv)
callDiv.style.padding = '1.5rem';
store.dispatch('updateIsLoading', true)
await store.dispatch('patientDetial',{id:patientId})
await store.dispatch('getAgentQuestionsAnswers',{patient_id:patientId})
username.value = store.getters.getPatientDetail.patient.first_name + ' ' + store.getters.getPatientDetail.patient.last_name;
email.value = store.getters.getPatientDetail.patient.email
phone.value = store.getters.getPatientDetail.patient.phone_no
dob.value = changeFormat(store.getters.getPatientDetail.patient.dob)
agePatient.value = calculateAge(store.getters.getPatientDetail.patient.dob) + " Year"
address1.value = store.getters.getPatientDetail.patient.address + ' ' +
store.getters.getPatientDetail.patient.city + ' ' +
store.getters.getPatientDetail.patient.state + ' ' +
store.getters.getPatientDetail.patient.country;
// address.value = patient_address;
answers.value = store.getters.getPatientAnswers
// console.log('questionsJsonData', questionsJsonData.value)
// console.log('API Answers', answers.value)
createFinalArray();
store.dispatch('updateIsLoading', false)
window.addEventListener('resize', checkMobile);
});
function changeFormat(dateFormat) {
const dateParts = dateFormat.split('-'); // Assuming date is in yyyy-mm-dd format
const year = parseInt(dateParts[0]);
const month = parseInt(dateParts[1]); // No need for padding
const day = parseInt(dateParts[2]); // No need for padding
// Create a new Date object with the parsed values
const date = new Date(year, month - 1, day); // Month is zero-based in JavaScript Date object
// Format the date as mm-dd-yyyy
const formattedDate = month + '-' + day + '-' + date.getFullYear();
return formattedDate;
}
// function changeFormat(dateFormat) {
// const dateParts = dateFormat.split('-'); // Assuming date is in yyyy-mm-dd format
// const year = parseInt(dateParts[0]);
// const month = String(dateParts[1]).padStart(2, '0'); // Pad single-digit months with leading zero
// const day = String(dateParts[2]).padStart(2, '0'); // Pad single-digit days with leading zero
// // Create a new Date object with the parsed values
// const date = new Date(year, month - 1, day); // Month is zero-based in JavaScript Date object
// // Format the date as mm-dd-yyyy
// const formattedDate = month + '-' + day + '-' + date.getFullYear();
// return formattedDate;
// }
const createFinalArray = () => {
questionsJsonData.value.forEach(question => {
const { label, key, type } = question;
if (answers.value.hasOwnProperty(key)) {
QuestionsAnswers.value.push({
label,
key,
type,
value: answers.value[key]
});
}
});
// console.log('------finalArray ', QuestionsAnswers.value)
};
const checkMobile = () => {
isMobile.value = window.innerWidth <= 768;
};
const calculateAge = (dateOfBirth) => {
const today = new Date();
const birthDate = new Date(dateOfBirth);
let age = today.getFullYear() - birthDate.getFullYear();
const monthDiff = today.getMonth() - birthDate.getMonth();
if (
monthDiff < 0 ||
(monthDiff === 0 && today.getDate() < birthDate.getDate())
) {
age--;
}
return age;
}
</script>
<template>
<v-row class='mb-2'>
<VCol cols="12" md="12" class="mb-4 " v-if="username || phone" style="font-size: 16px;">
<VCard>
<VCardText>
<h3 class="mb-2"> {{ username }}</h3>
<div class="mb-1">
<VTooltip location="left" activator="parent" transition="scroll-x-transition">
Email
</VTooltip>
<VIcon icon="ri-mail-line" size="20" class="me-2" />{{ email }}
</div>
<div class="mb-2">
<VTooltip location="left" activator="parent" transition="scroll-x-transition">
Age
</VTooltip>
<VIcon icon="ri-calendar-event-line" title="Age" size="20" class="me-2" />{{ agePatient }}
</div>
<div class="mb-2">
<VTooltip location="left" activator="parent" transition="scroll-x-transition">
Date of birth
</VTooltip>
<VIcon icon="ri-calendar-line" size="20" class="me-2" />{{ dob }}
</div>
<div class="mb-2">
<VTooltip location="left" activator="parent" transition="scroll-x-transition">
Address
</VTooltip>
<VIcon icon="ri-map-pin-line" size="20" class="me-2" />{{ address1 }}
</div>
<div>
<VTooltip location="left" activator="parent" transition="scroll-x-transition">
Contact Number
</VTooltip>
<VIcon icon="ri-phone-line" size="20" class="me-2" />{{ phone }}
</div>
</VCardText>
</VCard>
</VCol>
<v-col cols="12" md="12">
<VList class="">
<VListItem class="">
<VListItemTitle class="d-flex align-center justify-space-between bg-dark mt-1"
style="padding: 5px;">
<div :class="isMobile ? '' : 'w-40'">
<p class="mb-0" :class="isMobile ? 'heading-text-m' : 'heading-text-d'"><b>SYMPTOM
CHECKLIST</b></p>
</div>
<div class="d-flex align-center" :class="isMobile ? 'heading-text-m' : 'heading-text-d'">
<p class="mb-0"><b>MILD</b>
</p>
</div>
<div class="d-flex align-center" :class="isMobile ? 'heading-text-m' : 'heading-text-d'">
<p class="mb-0"><b>MODERATE</b>
</p>
</div>
<div class="d-flex align-center" :class="isMobile ? 'heading-text-m' : 'heading-text-d'">
<p class="mb-0"><b>SEVERE</b>
</p>
</div>
</VListItemTitle>
</VListItem>
<!-- Move the second list item inside the loop -->
<VListItem class="pt-0 pb-0 ht-li" v-for="(item, index) of QuestionsAnswers" :key="index">
<VListItemTitle class="d-flex align-center justify-space-between">
<div class="border-right"
:class="{ 'bg-silver': (index + 1) % 2 === 0, 'w-custom-m': isMobile, 'w-40': !isMobile }"
style="padding-left: 5px;">
<p class="text-wrap mb-0" :class="isMobile ? 'heading-text-m' : 'heading-text-d'">{{
item.label
}}</p>
</div>
<div class="d-flex align-center" :class="isMobile ? 'w-custom-d' : 'w-60'">
<QuestionProgressBar :type="item.type" :value="item.value"></QuestionProgressBar>
</div>
</VListItemTitle>
</VListItem>
</VList>
<!-- <v-table density="compact" fixed-header>
<thead>
<tr class="text-right">
<th class="bg-dark">
<b>SYMPTOM CHECKLIST</b>
</th>
<th class="text-right bg-dark">
<b>MILD</b>
<VIcon icon="mdi-menu-down"></VIcon>
</th>
<th class="text-right bg-dark">
<b>MODERATE</b>
<VIcon icon="mdi-menu-down"></VIcon>
</th>
<th class="text-right bg-dark">
<b>SEVERE</b>
<VIcon icon="mdi-menu-down"></VIcon>
</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) of QuestionsAnswers" :key="index">
<td class="border-right" v-if="!isMobile">{{ item.label }}</td>
<td :colspan="isMobile ? '4' : '3'">
<p v-if="isMobile" class="mb-0">{{ item.label }}</p>
<QuestionProgressBar :type="item.type" :value="item.value"></QuestionProgressBar>
</td>
</tr>
</tbody>
</v-table> -->
</v-col>
</v-row>
</template>
<style lang="scss" scoped>
.mdi-email {
margin-bottom: 5px;
}
.ht-li {
min-height: 20px !important;
}
.bg-silver {
background-color: silver;
}
.text-wrap {
text-wrap: balance;
}
.w-40 {
width: 40%;
}
.w-custom-m {
width: 36%;
}
.w-60 {
width: 60%;
}
.w-custom-d {
width: 65%;
}
.v-list-item--density-default.v-list-item--one-line {
min-height: 40px;
}
.heading-text-m {
font-size: 9px;
}
.heading-text-d {
font-size: 12px;
}
.bg-dark {
background-color: #808080b3 !important;
}
.text-right {
text-align: right !important;
width: 23%;
}
.border-right {
border-right: 1.5px solid black;
}
.hidden-component {
display: none
}
.meta-key {
border: thin solid rgba(var(--v-border-color), var(--v-border-opacity));
border-radius: 6px;
block-size: 1.5625rem;
line-height: 1.3125rem;
padding-block: 0.125rem;
padding-inline: 0.25rem;
}
::v-deep .custom-menu {
position: relative;
}
::v-deep .custom-menu::before {
content: "" !important;
position: absolute !important;
transform: translateY(-50%);
top: 50% !important;
left: -8px !important;
border-left: 8px solid transparent !important;
border-right: 8px solid transparent !important;
border-bottom: 8px solid #fff !important;
}
// Styles for the VList component
.more .v-list-item-title {
color: rgb(106 109 255);
}
.more .menu-item:hover {
cursor: pointer;
}
.slide-enter-active,
.slide-leave-active {
transition: transform 0.3s ease;
}
.slide-enter,
.slide-leave-to {
transform: translateX(-100%);
}
.start-call-btn {
opacity: 0;
display: none;
transition: opacity 0.3s ease;
}
.button_margin {
margin: 2px;
}
.dialog_padding {
padding: 5px;
}
.custom-menu .v-menu__content {
background-color: #333;
color: #fff;
border-radius: 4px;
padding: 8px 0;
}
.user-info {
display: flex;
flex-direction: column;
transition: opacity 0.3s ease;
}
.list-item-hover {
transition: background-color 0.3s ease;
&:hover {
background-color: rgba(var(--v-theme-primary), 0.1);
.start-call-btn {
opacity: 1;
display: block;
position: relative;
left: -35px;
}
.user-info {
opacity: 0;
display: none;
}
}
}
.pop_card {
overflow: hidden !important;
padding: 10px;
}
.v-overlay__content {
max-height: 706.4px;
max-width: 941.6px;
min-width: 24px;
--v-overlay-anchor-origin: bottom left;
transform-origin: left top;
top: 154.4px !important;
left: 204px !important;
}
.button_margin {
margin-top: 10px;
font-size: 10px;
}
/* Responsive Styles */
@media screen and (max-width: 768px) {
.pop_card {
max-width: 100%;
margin: 0 auto;
}
}
.container_img {
display: flex;
flex-direction: column;
width: 100%;
align-items: center;
}
.image {
order: 2;
/* Change the order to 2 in mobile view */
}
.text {
order: 1;
/* Change the order to 1 in mobile view */
}
/* Media query for mobile view */
@media (max-width: 768px) {
.container_img {
flex-direction: row;
margin-top: 10px;
}
.button_margin_mobile {
width: 100%;
}
.image {
width: 20%;
padding: 0 10px;
}
.text {
width: 80%;
/* Each takes 50% width */
padding: 0 10px;
/* Optional padding */
}
}
::-webkit-scrollbar {
width: 10px;
/* Width of the scrollbar */
}
/* Track */
::-webkit-scrollbar-track {
background: #f1f1f1;
/* Color of the track */
}
/* Handle */
::-webkit-scrollbar-thumb {
background: #888;
/* Color of the handle */
border-radius: 5px;
/* Roundness of the handle */
}
/* Handle on hover */
::-webkit-scrollbar-thumb:hover {
background: #555;
/* Color of the handle on hover */
}
/* Container for the content */
.scroll-container {
max-height: 191px;
/* Maximum height of the scrollable content */
overflow-y: scroll;
/* Enable vertical scrolling */
}
/* Content within the scroll container */
.scroll-content {
padding: 20px;
}
/* Example of additional styling for content */
.scroll-content p {
margin-bottom: 20px;
}
.cross button {
padding: 0px;
margin: 0px;
/* font-size: 10px; */
background: none;
border: none;
box-shadow: none;
height: 23px;
}
.v-data-table-header {
display: table-header-group;
}
</style>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,43 @@
{
"bp_match": {
"type": "c",
"values": {
"0": 100,
"60": 80,
"70": 60
}
},
"exact_match": {
"type": "e",
"values": {
"yes": 100,
"no": 2,
"high": 2,
"never": 2,
"almost_never": 30,
"occasionally": 66,
"almost_always": 75,
"always": 100,
"very_much": 66,
"a_lot": 100,
"a_little": 30,
"not_at_all": 2,
"not_applicable": 2,
"rarely": 30,
"sometimes": 66,
"often": 75,
"unsure": 2,
"less_than_6_hrs": 100,
"six_to_eight_hrs": 66,
"more_than_eight": 33,
"before_penetrate": 100,
"ejaculate_early": 66,
"no_issue_with_ejaculation": 2,
"no_issue": 2,
"usually_difficult": 100,
"low": 100,
"medium": 66,
"none_of_above_them": 2
}
}
}

View File

@ -47,13 +47,9 @@ const headers = [
{ key: 'start_time', title: 'Start Time' },
{ key: 'end_time', title: 'End Time' },
{ key: 'duration', title: 'Duration' },
// { title: 'ACTIONS', key: 'actions' },
{ title: 'Actions', key: 'profile' }, // Add this line
];
function totalCallDuration(start_time, end_time) {
const startMoment = moment(start_time);
const endMoment = moment(end_time);
@ -115,6 +111,12 @@ const historyDetail = (item, value) => {
if(value == 'prescription')
router.push('/admin/patient/meeting/prescription/' + route.params.id + '/' + item.id);
}
const viewProfile = (item) => {
console.log('Viewing profile for', item);
// Navigate to the profile page (modify the route as per your application structure)
router.push('/admin/providers/patientprofile/' + item.patient_id);
}
const menusVariant = [
'primary'
];
@ -162,6 +164,10 @@ const options = [
>
<template #item.id="{ item }">{{ item.id }}</template>
<template #item.duration="{ item }">{{ item.duration }}</template>
<!-- Profile Button -->
<template #item.profile="{ item }">
<v-btn class="text-capitalize text-white" @click="viewProfile(item)">Profile</v-btn>
</template>
<!-- Actions -->
<template #item.actions="{ item }">
<div class="demo-space-x">

View File

@ -123,6 +123,11 @@ export const routes = [
name: 'admin-provider-profile',
component: () => import('@/pages/providers/provider-profile.vue'),
},
{
path: '/admin/providers/patientprofile/:patient_id',
name: 'admin-providers-patientprofile',
component: () => import('@/pages/patients/patientprofile.vue'),
},
{
path: '/apps/email/filter/:filter',
name: 'apps-email-filter',

View File

@ -8,6 +8,7 @@ import {
ADMIN_LAB_KIT_UPDATE_API,
ADMIN_LOGIN_DETAIL,
ADMIN_PATIENT_DETAIL_API,
ADMIN_PATIENT_PROFILE_API,
ADMIN_PROVIDER_DETAIL_API,
ADMIN_UPDATE_PASSWORD,
ADMIN_UPDATE_SITE_SETTING,
@ -65,7 +66,8 @@ export default createStore({
checkLoginExpire: false,
labKitList: [],
patientDetail: null,
providerDetail:null
providerDetail:null,
patientAnswers: null,
},
mutations: {
setLoading(state, payload) {
@ -161,7 +163,9 @@ export default createStore({
setPatientPrescriptionStatus(state, payload) {
state.patientPrescriptionStatus = payload
},
setPatientAnswers(state, payload) {
state.patientAnswers = payload
},
@ -1013,6 +1017,24 @@ export default createStore({
console.error('Error:', error);
});
},
async getAgentQuestionsAnswers ({commit},payload){
commit('setLoading', true)
await axios.post(ADMIN_PATIENT_PROFILE_API+payload.patient_id, {}, {
headers: {
'Authorization': `Bearer ${localStorage.getItem('admin_access_token')}`,
}
})
.then(response => {
commit('setLoading', false)
console.log('Response:', response.data.data);
commit('setPatientAnswers', response.data.data)
})
.catch(error => {
commit('setLoading', false)
console.log('Error:', error);
});
},
},
getters: {
getIsLoading(state){
@ -1090,5 +1112,8 @@ export default createStore({
getProviderDetail(state) {
return state.providerDetail
},
getPatientAnswers(state){
return state.patientAnswers
},
}
})

2
typed-router.d.ts vendored
View File

@ -161,8 +161,10 @@ declare module 'vue-router/auto/routes' {
'patients-patient-profile': RouteRecordInfo<'patients-patient-profile', '/patients/patient-profile', Record<never, never>, Record<never, never>>,
'patients-patien-tab-overview': RouteRecordInfo<'patients-patien-tab-overview', '/patients/PatienTabOverview', Record<never, never>, Record<never, never>>,
'patients-patient-bio-panel': RouteRecordInfo<'patients-patient-bio-panel', '/patients/PatientBioPanel', Record<never, never>, Record<never, never>>,
'patients-patientprofile': RouteRecordInfo<'patients-patientprofile', '/patients/patientprofile', Record<never, never>, Record<never, never>>,
'patients-patients': RouteRecordInfo<'patients-patients', '/patients/patients', Record<never, never>, Record<never, never>>,
'patients-prescription-panel': RouteRecordInfo<'patients-prescription-panel', '/patients/PrescriptionPanel', Record<never, never>, Record<never, never>>,
'patients-question-progress-bar': RouteRecordInfo<'patients-question-progress-bar', '/patients/QuestionProgressBar', Record<never, never>, Record<never, never>>,
'providers-completed-meeting-tab': RouteRecordInfo<'providers-completed-meeting-tab', '/providers/CompletedMeetingTab', Record<never, never>, Record<never, never>>,
'providers-meeting-details': RouteRecordInfo<'providers-meeting-details', '/providers/meeting-details', Record<never, never>, Record<never, never>>,
'providers-meetings': RouteRecordInfo<'providers-meetings', '/providers/meetings', Record<never, never>, Record<never, never>>,