Interface SAV
This commit is contained in:
92
src/App.vue
92
src/App.vue
@@ -1,26 +1,26 @@
|
||||
<script setup>
|
||||
import TicketList from '@/components/TicketList.vue'
|
||||
import Modal from "@/components/base/Modal.vue";
|
||||
import {computed, nextTick, onMounted, ref, watch} from 'vue';
|
||||
import {Tab} from 'bootstrap'
|
||||
import TicketApi from "@/services/TicketApi.js";
|
||||
import {useGlobalStore} from "@/stores/global";
|
||||
import {onMounted, ref} from 'vue';
|
||||
import {storeToRefs} from "pinia";
|
||||
import {useGlobalStore} from "@/stores/global";
|
||||
import {useTicketStore} from "@/stores/ticket";
|
||||
import {showModal, hideModal} from "@/setup/global.js";
|
||||
import {Tab} from 'bootstrap'
|
||||
import Messenger from "@/components/Messenger.vue";
|
||||
import {showModal, hideModal, idTicket, codeTicket} from "@/setup/global.js";
|
||||
import TicketList from '@/components/TicketList.vue'
|
||||
import Modal from '@/components/base/Modal.vue'
|
||||
|
||||
const store = useGlobalStore()
|
||||
const storeTicket = useTicketStore();
|
||||
const {
|
||||
newTickets,
|
||||
pendingTickets,
|
||||
myTickets,
|
||||
originFilter,
|
||||
idTicket,
|
||||
currentTicket,
|
||||
} = storeToRefs(storeTicket)
|
||||
|
||||
const filter = ref('ALL');
|
||||
const tickets = ref({});
|
||||
const apiCounter = ref(0)
|
||||
const waitingPromise = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
resolve([]);
|
||||
}, 100000);
|
||||
});
|
||||
}
|
||||
|
||||
const openExternalPage = async (script, params = null, features = null) => {
|
||||
if (store.gulliver === null) {
|
||||
@@ -29,46 +29,30 @@ const openExternalPage = async (script, params = null, features = null) => {
|
||||
window.open(store.url + script + '?NUMC=' + store.numc + (params !== null ? '&' + params : ''), '_blank', features);
|
||||
}
|
||||
|
||||
const newTickets = computed(() => {
|
||||
return tickets.value.hasOwnProperty('new_tickets') ? mapListOfTickets(tickets.value.new_tickets.list, filter.value) : waitingPromise
|
||||
})
|
||||
|
||||
const pendingTickets = computed(() => {
|
||||
return tickets.value.hasOwnProperty('pending_tickets') ? mapListOfTickets(tickets.value.pending_tickets.list, filter.value) : []
|
||||
})
|
||||
|
||||
const myTickets = computed(() => {
|
||||
return tickets.value.hasOwnProperty('my_tickets') ? mapListOfTickets(tickets.value.my_tickets.list, filter.value) : []
|
||||
})
|
||||
|
||||
const mapListOfTickets = (tickets, originFilter) => {
|
||||
return tickets.filter(ticket => ((originFilter !== 'ALL') ? ticket.origin === originFilter : true)).map(ticket =>
|
||||
[ticket.code, ticket.datetime, ticket.filter1, ticket.filter2, ticket, ticket.advisor, ticket.datetime, ticket.state2, ticket.first_name + ' ' + ticket.last_name, ticket.is_customer]);
|
||||
const waitingPromise = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
resolve([]);
|
||||
}, 100000);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
const currentTicket = computed(()=>{
|
||||
|
||||
const vracTickets = [
|
||||
...tickets.value.my_tickets.list,
|
||||
...tickets.value.pending_tickets.list,
|
||||
...tickets.value.new_tickets.list
|
||||
]
|
||||
|
||||
const currentTickets = vracTickets.filter(t=>t.id === idTicket.value)
|
||||
|
||||
return (currentTickets.length === 1) ? currentTickets[0] : []
|
||||
|
||||
})
|
||||
const mapListOfTickets = (tickets) => {
|
||||
return tickets.map(ticket =>
|
||||
[ticket.code, ticket.datetime, ticket.filter1, ticket.filter2, ticket, ticket.advisor, ticket.datetime, ticket.state2, ticket.first_name + ' ' + ticket.last_name, ticket.is_customer]);
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
tickets.value = await TicketApi.getTickets()
|
||||
await store.registerUserSession();
|
||||
await storeTicket.registerTicketList()
|
||||
apiCounter.value++
|
||||
|
||||
const myInterval = setInterval(async function () {
|
||||
tickets.value = await TicketApi.getTickets()
|
||||
await storeTicket.registerTicketList()
|
||||
apiCounter.value++
|
||||
}, 180000);
|
||||
|
||||
})
|
||||
|
||||
</script>
|
||||
@@ -78,10 +62,11 @@ onMounted(async () => {
|
||||
|
||||
<Modal :show="showModal" :hide="hideModal" size="modal-fullscreen">
|
||||
<template v-slot:modal-title>
|
||||
<h2 v-if="idTicket !== 0">Fiche n° {{idTicket}} - {{currentTicket.first_name}} {{currentTicket.last_name}}</h2>
|
||||
<h2 v-if="idTicket !== 0">Fiche n° {{ idTicket }} - {{ currentTicket.first_name }}
|
||||
{{ currentTicket.last_name }}</h2>
|
||||
</template>
|
||||
<template v-slot:modal-body>
|
||||
<Messenger :key="showModal" v-if="showModal" :id-ticket="idTicket" :code-ticket="codeTicket"></Messenger>
|
||||
<Messenger :key="showModal" v-if="showModal"></Messenger>
|
||||
</template>
|
||||
</Modal>
|
||||
|
||||
@@ -92,7 +77,6 @@ onMounted(async () => {
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
|
||||
<ul class="nav">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" aria-current="page" href="#"
|
||||
@@ -153,7 +137,7 @@ onMounted(async () => {
|
||||
<label for="origineFilter" class="col-auto col-form-label fw-bold"><i class="fa-solid fa-filter"></i>
|
||||
Filtrer par origine</label>
|
||||
<div class="col-auto">
|
||||
<select class="form-select" id="origineFilter" v-model="filter">
|
||||
<select class="form-select" id="origineFilter" v-model="originFilter">
|
||||
<option value="ALL">Toute</option>
|
||||
<option value="ORDER">Commande</option>
|
||||
<option value="CONTACT">Fiche contact</option>
|
||||
@@ -164,13 +148,15 @@ onMounted(async () => {
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab-pane show active" id="new" role="tabpanel" tabindex="0">
|
||||
<ticket-list :rows="newTickets" :key="'new_'+filter+'_'+apiCounter"></ticket-list>
|
||||
<ticket-list :rows="mapListOfTickets(newTickets)"
|
||||
:key="'new_'+originFilter+'_'+apiCounter"></ticket-list>
|
||||
</div>
|
||||
<div class="tab-pane" id="pending" role="tabpanel" tabindex="0">
|
||||
<ticket-list :rows="pendingTickets" :key="'new_'+filter+'_'+apiCounter"></ticket-list>
|
||||
<ticket-list :rows="mapListOfTickets(pendingTickets)"
|
||||
:key="'new_'+originFilter+'_'+apiCounter"></ticket-list>
|
||||
</div>
|
||||
<div class="tab-pane" id="my" role="tabpanel" tabindex="0">
|
||||
<ticket-list :rows="myTickets" :key="'new_'+filter+'_'+apiCounter"></ticket-list>
|
||||
<ticket-list :rows="mapListOfTickets(myTickets)" :key="'new_'+originFilter+'_'+apiCounter"></ticket-list>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,88 +1,109 @@
|
||||
<script setup>
|
||||
import TicketApi from "@/services/TicketApi.js";
|
||||
import {onMounted, ref} from 'vue';
|
||||
import {codeTicket} from "@/setup/global";
|
||||
import {format, formatDistance} from "date-fns";
|
||||
import {fr} from 'date-fns/locale';
|
||||
|
||||
const props = defineProps({
|
||||
idTicket: [Number,String],
|
||||
codeTicket : [Number,String],
|
||||
})
|
||||
import {useTicketStore} from "@/stores/ticket";
|
||||
|
||||
const storeTicket = useTicketStore();
|
||||
|
||||
const messages = ref([])
|
||||
|
||||
onMounted(async () => {
|
||||
messages.value = await TicketApi.getMessages(props.codeTicket, props.idTicket)
|
||||
messages.value = await TicketApi.getMessages(storeTicket.currentTicket.codeTicket, storeTicket.idTicket)
|
||||
})
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="messages.length >0" class="container-fluid">
|
||||
<div v-if="messages.length >0" class="container-fluid">
|
||||
|
||||
<div class="col-lg-12">
|
||||
<div class="chat-app">
|
||||
<div id="plist" class="people-list">
|
||||
<div class="col-lg-12">
|
||||
<div class="chat-app">
|
||||
<div id="plist" class="people-list">
|
||||
|
||||
Menu / to do
|
||||
Menu / to do
|
||||
|
||||
</div>
|
||||
<div class="chat">
|
||||
<div class="chat-header clearfix">
|
||||
<div class="row">
|
||||
<div class="col-lg-6">
|
||||
<a href="javascript:void(0);" data-toggle="modal" data-target="#view_info">
|
||||
<img src="https://bootdey.com/img/Content/avatar/avatar2.png" alt="avatar">
|
||||
</a>
|
||||
<div class="chat-about">
|
||||
<h6 class="m-b-0">Aiden Chavez</h6>
|
||||
<small>Last seen: 2 hours ago</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6 hidden-sm text-end">
|
||||
<a href="javascript:void(0);" class="btn btn-outline-secondary me-2"><i class="fa-solid fa-camera"></i></a>
|
||||
<a href="javascript:void(0);" class="btn btn-outline-primary me-2"><i class="fa-solid fa-image"></i></a>
|
||||
<a href="javascript:void(0);" class="btn btn-outline-info me-2"><i class="fa-solid fa-cogs"></i></a>
|
||||
<a href="javascript:void(0);" class="btn btn-outline-warning"><i class="fa-solid fa-question"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="chat-history">
|
||||
<ul class="m-b-0">
|
||||
</div>
|
||||
<div class="chat">
|
||||
<div class="chat-header clearfix">
|
||||
<div class="row">
|
||||
<div class="col-lg-6">
|
||||
<a href="javascript:void(0);" data-toggle="modal" data-target="#view_info">
|
||||
<img src="https://bootdey.com/img/Content/avatar/avatar2.png" alt="avatar">
|
||||
</a>
|
||||
<div class="chat-about">
|
||||
<h6 class="m-b-0">Aiden Chavez</h6>
|
||||
<small>Last seen: 2 hours ago</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="chat-history">
|
||||
<ul class="m-b-0">
|
||||
|
||||
<li class="clearfix" v-for="(message, i) in messages" :key="i">
|
||||
<div class="message-data" :class="message.sender === 'pharma' ? 'text-end' : ''">
|
||||
<span class="message-data-time">{{message.date}}</span>
|
||||
<i class="fa-solid fa-circle-user ms-2 fa-2x text-primary" v-if="message.sender === 'client'"></i>
|
||||
</div>
|
||||
<div class="message" :class="message.sender === 'pharma' ? 'other-message float-end' : 'my-message'">
|
||||
<li class="clearfix" v-for="(message, i) in messages" :key="i">
|
||||
<div class="message-data" :class="message.sender === 'pharmacy' ? 'text-end' : ''">
|
||||
|
||||
<strong v-if="message.object !== null">{{message.object}}<br/></strong>
|
||||
<Icon icon="ph:user-light" width="40" class="text-primary" v-if="message.sender === 'client'"/>
|
||||
|
||||
<div v-if="message.htmlBody !== null" v-html="message.htmlBody"></div>
|
||||
<div v-else>{{message.body}}</div>
|
||||
<span class="message-data-time">{{
|
||||
format(new Date(message.date), 'dd MMMM yyyy à HH:mm', {
|
||||
addSuffix: true,
|
||||
locale: fr
|
||||
})
|
||||
}}</span>
|
||||
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<Icon icon="mdi:support" width="40" class="text-success ms-2" v-if="message.sender === 'pharmacy'"/>
|
||||
|
||||
<div class="chat-message clearfix">
|
||||
<div class="input-group mb-3">
|
||||
<span class="input-group-text"><i class="fa-solid fa-paper-plane"></i></span>
|
||||
<input type="text" class="form-control" placeholder="Entrer votre réponse">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="message" :class="message.sender === 'pharmacy' ? 'other-message float-end' : 'my-message'">
|
||||
|
||||
<div v-if="message.htmlBody !== null">
|
||||
<strong v-if="message.object !== null ">{{ message.object }}<br/></strong>
|
||||
<div v-html="message.htmlBody"></div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<strong v-if="message.object !== null && message.body === null">{{ message.object }}<br/></strong>
|
||||
{{ message.body }}
|
||||
</div>
|
||||
|
||||
<div v-if="message.document.length >0">
|
||||
<a class="btn me-2 mt-2" :class="document.color" v-for="(document, i) in message.document"
|
||||
:key="'document-'+i"
|
||||
:href="'https://gta.parapharmacie-et-medicament.com/interface/ase_get_doc.php?prj=pharmamp&id='+document.id">
|
||||
<Icon width="40" :icon="document.icon"></Icon>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div v-else class="text-center mt-5">
|
||||
<i class="fa-solid fa-circle-notch fa-spin fa-fw text-primary fa-4x"></i>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-12 hidden-sm text-end" style="padding: 20px">
|
||||
<a href="javascript:void(0);" class="btn btn-outline-secondary me-2"><i class="fa-solid fa-camera"></i></a>
|
||||
<a href="javascript:void(0);" class="btn btn-outline-primary me-2"><i class="fa-solid fa-image"></i></a>
|
||||
<a href="javascript:void(0);" class="btn btn-outline-info me-2"><i class="fa-solid fa-cogs"></i></a>
|
||||
<a href="javascript:void(0);" class="btn btn-outline-warning"><i class="fa-solid fa-question"></i></a>
|
||||
</div>
|
||||
<div class="chat-message clearfix">
|
||||
<div class="input-group mb-3">
|
||||
<span class="input-group-text"><i class="fa-solid fa-paper-plane"></i></span>
|
||||
<input type="text" class="form-control" placeholder="Entrer votre réponse">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<div v-else class="text-center mt-5">
|
||||
<i class="fa-solid fa-circle-notch fa-spin fa-fw text-primary fa-4x"></i>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
<script setup>
|
||||
import {computed, nextTick, onMounted, ref, watch} from 'vue';
|
||||
import {showModal, hideModal, idTicket, codeTicket} from "@/setup/global.js";
|
||||
import {onMounted, ref, watch} from 'vue';
|
||||
import {showModal, hideModal} from "@/setup/global.js";
|
||||
import {useTicketStore} from "@/stores/ticket";
|
||||
|
||||
import {format, formatDistance} from "date-fns";
|
||||
import {fr} from 'date-fns/locale';
|
||||
|
||||
import {Grid, html, h} from "gridjs";
|
||||
import {Tooltip} from 'bootstrap'
|
||||
|
||||
const storeTicket = useTicketStore();
|
||||
|
||||
const props = defineProps({
|
||||
rows: {type: [Array, Function]},
|
||||
})
|
||||
@@ -36,7 +40,7 @@ const grid = new Grid({
|
||||
formatter: (cell, row) => {
|
||||
return h('i', {
|
||||
className: 'fas fa-eye text-primary cursor-pointer',
|
||||
onClick: () => {showModal.value++; idTicket.value = row.cells[4].data.id; codeTicket.value = row.cells[4].data.code} // id_last_event
|
||||
onClick: () => {showModal.value++; storeTicket.setIdTicket(row.cells[4].data.id)} // id_last_event
|
||||
}, '');
|
||||
|
||||
},
|
||||
|
||||
@@ -12,12 +12,14 @@ import '@fortawesome/fontawesome-free/css/solid.css'
|
||||
import '@fortawesome/fontawesome-free/css/regular.css'
|
||||
import "gridjs/dist/theme/mermaid.css";
|
||||
|
||||
import { Icon } from '@iconify/vue';
|
||||
|
||||
const pinia = createPinia()
|
||||
|
||||
const app = createApp(App)
|
||||
//app.use(router);
|
||||
app.use(pinia)
|
||||
//app.component('Datepicker', Datepicker);
|
||||
app.component('Icon', Icon);
|
||||
app.mount("#app");
|
||||
|
||||
|
||||
|
||||
@@ -2,5 +2,3 @@ import {ref} from "vue";
|
||||
|
||||
export const showModal = ref(0)
|
||||
export const hideModal = ref(0)
|
||||
export const idTicket = ref(0)
|
||||
export const codeTicket = ref(0)
|
||||
|
||||
@@ -3,15 +3,21 @@ import Api from "@/services/Api.js";
|
||||
|
||||
export const useGlobalStore = defineStore('global', {
|
||||
state: () => ({
|
||||
gulliver: null
|
||||
gulliver: null,
|
||||
gta: {idProject: null, projectName: null},
|
||||
}),
|
||||
getters: {
|
||||
numc: (state) => state.gulliver.numc,
|
||||
url : (state) => state.gulliver.url,
|
||||
url: (state) => state.gulliver.url,
|
||||
idProject: (state) => state.gta.idProject,
|
||||
projectName: (state) => state.gta.projectName,
|
||||
},
|
||||
actions: {
|
||||
async registerSession(){
|
||||
async registerSession() {
|
||||
this.gulliver = await Api.call('AdminController', 'getSession')
|
||||
},
|
||||
async registerUserSession() {
|
||||
this.gta = {...await Api.call('AdminController', 'getUserSession')}
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
import {defineStore} from 'pinia'
|
||||
import TicketApi from "@/services/TicketApi";
|
||||
|
||||
const splitTicketList = (ticketList, pileName, filter) => {
|
||||
return (ticketList.hasOwnProperty(pileName)) ? ticketList[pileName].list.filter(ticket => ((filter !== 'ALL') ? ticket.origin === filter : true)) : []
|
||||
}
|
||||
|
||||
export const useTicketStore = defineStore('ticket', {
|
||||
state: () => ({
|
||||
ticketList: [],
|
||||
originFilter: 'ALL',
|
||||
idTicket: 0,
|
||||
codeTicket: 0
|
||||
}),
|
||||
getters: {
|
||||
newTickets: (state) => splitTicketList(state.ticketList, 'new_tickets', state.originFilter),
|
||||
pendingTickets: (state) => splitTicketList(state.ticketList, 'pending_tickets', state.originFilter),
|
||||
myTickets: (state) => splitTicketList(state.ticketList, 'my_tickets', state.originFilter),
|
||||
currentTicket: (state) => {
|
||||
return [
|
||||
...splitTicketList(state.ticketList, 'new_tickets', state.originFilter),
|
||||
...splitTicketList(state.ticketList, 'pending_tickets', state.originFilter),
|
||||
...splitTicketList(state.ticketList, 'my_tickets', state.originFilter)
|
||||
].filter(t => t.id === state.idTicket)[0]
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
async registerTicketList() {
|
||||
this.ticketList = await TicketApi.getTickets()
|
||||
},
|
||||
setIdTicket(id) {
|
||||
this.idTicket = id
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user